close

【參考1】CreateThread, AfxBeginThread,_beginthread, _beginthreadex的區別 =====================================================================

1、CreateThread——Windows的API函數
2、_beginthreadex——MS對C Runtime庫的擴展SDK函數
3、AfxBeginThread——MFC中線程創建的MFC函數

CreateThread
(API函數:SDK函數的標準形式,直截了當的創建方式,任何場合都可以使用。)
提供操作系統級別的創建線程的操作,且僅限於工作者線程。不調用MFC和RTL的函數時,可以用CreateThread,其它情況不要輕易。在使用的過程中要考慮到進程的同步與互斥的關係(防止死鎖)。
線程函數定義為:DWORD WINAPI _yourThreadFun(LPVOID pParameter)。
但它沒有考慮:
(1)C Runtime中需要對多線程進行紀錄和初始化,以保證C函數庫工作正常(典型的例子是strtok函數)。
(2)MFC也需要知道新線程的創建,也需要做一些初始化工作(當然,如果沒用MFC就沒事了)。  

_beginthreadex
MS對C Runtime庫的擴展SDK函數,首先針對C Runtime庫做了一些初始化的工作,以保證C Runtime庫工作正常。然後,調用CreateThread真正創建線程。 僅使用Runtime Library時,可以用_BegingThread。

AfxBeginThread
MFC中線程創建的MFC函數,首先創建了相應的CWinThread對象,然後調用CWinThread::CreateThread,   在CWinThread::CreateThread中,完成了對線程對象的初始化工作,然後,調用_beginthreadex(AfxBeginThread相比較更為安全)創建線程。它簡化了操作或讓線程能夠響應消息,即可用於界麵線程,也可以用於工作者線程,但要注意不要在一個MFC程序中使用_beginthreadex()或CreateThread()。
線程函數定義為:UINT _yourThreadFun(LPVOID pParam)

=====================================================================

【參考2】CreateThread與_beginthreadex
=====================================================================

CreateThread
「CreateThread函數是用來創建線程的Windows函數不過,如果你正在編寫C/C++代碼,決不應該調用CreateThread。相反,應該使用Visual C++運行期庫函數_beginthreadex。如果不使用Microsoft的Visual C++編譯器,你的編譯器供應商有它自己的CreateThred替代函數。不管這個替代函數是什麼,你都必須使用。」

_beginthreadex
"_beginthreadex函數的參數列表與CreateThread函數的參數列表是相同的,但是參數名和類型並不完全相同。這是因為 Microsoft的C/C++運行期庫的開發小組認為, C/C++運行期函數不應該對Windows數據類型有任何依賴。_beginthreadex函數也像CreateThread那樣,返回新創建的線程的句柄。因此,如果調
用源代碼中的CreateThread,就很容易用對_beginthreadex的調用全局取代所有這些調用。不過,由於數據類型並不完全相同,所以必須進行某種轉換,使編譯器運行得順利些。" 
"下面是關於_beginthreadex的一些要點: 
1) 每個線程均獲得由C/C++運行期庫的堆棧分配的自己的tiddata內存結構。(tiddata結構位於Mtdll.h文件中的Visual C++源代碼中)。 
2) 傳遞給_beginthreadex的線程函數的地址保存在tiddata內存塊中。傳遞給該函數的參數也保存在該數據塊中。 
3) _beginthreadex確實從內部調用CreateThread,因為這是操作系統瞭解如何創建新線程的唯一方法。 
4) 當調用CreatetThread時,它被告知通過調用_threadstartex而不是pfnStartAddr來啟動執行新線程。還有,傳遞給線程函數的參數是tiddata結構而不是pvParam的地址。 
5) 如果一切順利,就會像CreateThread那樣返回線程句柄。如果任何操作失敗了,便返回NULL。"

為什麼?
  「也許你想知道,如果調用CreateThread,而不是調用C/C++運行期庫的_beginthreadex來創建新線程,將會發生什麼情況。當一個線程調用要求tiddata結構的C/C++運行期庫函數時,將會發生下面的一些情況(大多數C/C++運行期庫函數都是線程安全函數,不需要該結構)。
  首先,C/C++運行期庫函數試圖(通過調用TlsGetValue)獲取線程的數據塊的地址。如果返回NULL作為tiddata塊的地址,調用線程就不擁有與該地址相關的tiddata塊。這時,C/C++運行期庫函數就在現場為調用線程分配一個tiddata塊,並對它進行初始化。然後該 tiddata塊(通過TlsSetValue)與線程相關聯。此時,只要線程在運行,該tiddata將與線程待在一起。這時,C/C++運行期庫函數就可以使用線程的tiddata塊,而且將來被調用的所有C/C++運行期函數也能使用tiddata塊。 
  當然,這看來有些奇怪,因為線程運行時幾乎沒有任何障礙。不過,實際上還是存在一些問題。首先,如果線程使用C/C++運行期庫的signal函數,那麼整個進程就會終止運行,因為結構化異常處理幀尚未準備好。第二,如果不是調用_endthreadex來終止線程的運行,那麼數據塊就不會被撤消,內存洩漏就會出現(那麼誰還為使用CreateThread函數創建的線程來調用_endthreadex呢?)。 
   注意如果程序模塊鏈接到多線程DLL版本的C/C++運行期庫,那麼當線程終止運行並釋放tiddata塊(如果已經分配了tiddata塊的話)時,該運行期庫會收到一個DLL_THREAD_DETACH通知。儘管這可以防止tiddata塊的洩漏,但是強烈建議使用_beginthreadex而不是使用Createthread來創建線程。

=====================================================================

【參考3】關於_beginthreadex和CreateThread的區別
=====================================================================

  在 Win32 API 中,創建線程的基本函數是 CreateThread,而 _beginthread(ex) 是C++ 運行庫的函數。為什麼要有兩個呢?因為C++ 運行庫裡面有一些函數使用了全局量,如果使用 CreateThread 的情況下使用這些C++ 運行庫的函數,就會出現不安全的問題。而 _beginthreadex 為這些全局變量做了處理,使得每個線程都有一份獨立的「全局」量。
  所以,如果你的編程只調用 Win32 API/SDK ,就放心用 CreateThread;如果要用到C++ 運行時間庫,那麼就要使用 _beginthreadex ,並且需要在編譯環境中選擇 Use MultiThread Lib/DLL。
  通常他們的解釋都是這容易造成內存洩漏。這個解釋本身是沒有錯的,但是解釋得不夠完全和詳細。以至於造成很多新手盲目的信任了那句話,在那裡都是用_beginthreadex函數,或者是裝作沒有看到使用CreateThread函數。曾經有一段時間我也對這個問題很是困惑,不知道到底用那個才是對的。因為我不止一次在很多權威性的代碼中看到對CreateThread函數的直接調用。難道是權威錯了?? 抱著懷疑的態度查找了大量的資料和書籍,終於搞明白了這個問題的關鍵所在,在此做個說明,算是對那句話的一個完善。
  關於_beginthreadex和CreateThread的區別我就不做說明了,這個很容易找到的。我們只要知道一個問題:_beginthreadex是一個C運行時庫的函數,CreateThread是一個系統API函數,_beginthreadex內部調用了CreateThread。只所以所有的書都強調內存洩漏的問題是因為_beginthreadex函數在創建線程的時候分配了一個堆結構並和線程本身關聯起來,我們把這個結構叫做tiddata結構,是通過線程本地存儲器TLS於線程本身關聯起來。我們傳入的線程入口函數就保存在這個結構中。tiddata的作用除了保存線程函數入口地址之外,還有一個重要的作用就是:C運行時庫中有些函數需要通過這個結構來保存和獲取一些數據,比如說errno之類的線程全局變量。這點才是最重要的。
  當一個線程調用一個要求tiddata結構的運行時庫函數的時候,將發生下面的情況:
  運行時庫函數試圖TlsGetv alue獲取線程數據塊的地址,如果沒有獲取到,函數就會現場分配一個 tiddata結構,並且和線程相關聯,於是問題出現了,如果不通過_endthreadex函數來終結線程的話,這個結構將不會被撤銷,內存洩漏就會出現了。但通常情況下,我們都不推薦使用_endthreadex函數來結束線程,因為裡面包含了ExitThread調用。
  找到了內存洩漏的具體原因,我們可以這樣說:只要在創建的線程裡面不使用一些要求tiddata結構的運行時庫函數,我們的內存時安全的。所以,前面說的那句話應該這樣說才完善:
  「絕對不要調用系統自帶的CreateThread函數創建新的線程,而應該使用_beginthreadex,除非你在線程中絕不使用需要tiddata結構的運行時庫函數」
  這個需要tiddata結構的函數有點麻煩了,在侯捷的《win32多線程程序設計》一書中這樣說到:
   如果在除主線程之外的任何線程中進行一下操作,你就應該使用多線程版本的C runtime library,並使用_beginthreadex和_endthreadex:
   1 使用malloc()和free(),或是new和delete
   2 使用stdio.h或io.h裡面聲明的任何函數
   3 使用浮點變量或浮點運算函數
   4 調用任何一個使用了靜態緩衝區的runtime函數,比如:asctime(),strtok()或rand()

=====================================================================

【參考4】_beginthreadex、CreateThread、AfxBeginThread的選擇=====================================================================

1. Create/EndThread是Win32方法開始/結束一個線程
_beginthreadx/_endthreadex是C RunTime方式開始/結束一個線程
AfxBeginThread在MFC中開始/結束一個線程

2.直接在CreateThread API創建的線程中使用sprintf,malloc,strcat等涉及CRT存儲堆操作的CRT庫函數是很危險的,容易造成線程的意外中止。 在使用_beginthread和_beginthreadex創建的線程中可以安全的使用CRT函數。但是必須在線程結束的時候相應的調用_endthread或_endthreadex

3._beginthread成對調用的_endthread函數內部隱式的調用CloseHandle關閉了線程句柄,而與_beginthreadex成對使用的_endthreadex則沒有關閉線程的句柄,需要顯示的調用CloseHandle關閉線程句柄,不要使用_beginthread,使用._beginthreadex代替之。

4.儘量不要在一個MFC程序中使用_beginthreadex()或CreateThread()。

5.沒有使用到MFC的線程儘量用_beginthreadex啟動。

6.如果在一個與LIBCMT.LIB鏈接的程序中調用C Runtime函數,則必須要用_beginthreadex啟動線程

7._beginthreadex啟動的線程可以安全的調用任何C Runtime 函數

=====================================================================

【參考5】CreateThread()、_beginthread()以及_beginthreadex()聯繫與區別
=====================================================================

<>中有很詳細地介紹:
注意:若要創建一個新線程,絕對不要使用CreateThread,而應使用_beginthreadex.
Why?考慮標準C運行時庫的一些變量和函數,如errno,這是一個全局變量。全局變量用於多線程會出什麼事,你一定知道的了。故必須存在一種機制,使得每個線程能夠引用它自己的errno變量,又不觸及另一線程的errno變量._beginthreadex就為每個線程分配自己的tiddata內存結構。該結構保存了許多像errno這樣的變量和函數的值、地址(自己看去吧)。
通過線程局部存儲將tiddata與線程聯繫起來。具體實現在Threadex.c中有。   
結束線程使用函數_endthreadex函數,釋放掉線程的tiddata數據塊。   
CRT的函數庫在線程出現之前就已經存在,所以原有的CRT不能真正支持線程,這導致我們在編程的時候有了CRT庫的選擇,在MSDN中查閱CRT的函數時都有:
  Libraries   
  LIBC.LIB   Single   thread   static   library,   retail   version     
  LIBCMT.LIB   Multithread   static   library,   retail   version     
  MSVCRT.LIB   Import   library   for   MSVCRT.DLL,   retail   version     
這樣的提示!

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 figer 的頭像
    figer

    日劇看不完

    figer 發表在 痞客邦 留言(0) 人氣()