【參考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
這樣的提示!