天天看點

采用_beginthread/_beginthreadex函數建立多線程

1、CRT簡介:

CRT: (C Runtime Library)即C運作時庫,是系統運作的基礎,包含了c常用的函數集(如:printf,malloc,strcpy等),為運作main做了初始化環境變量、堆、io等資源,并在結束後清理。

在Windows環境下,VC提供的 C run-time library又分為動态運作時庫、靜态運作時庫、多線程、單線程、調試版本(Debug)、發行版本(Release)等。

采用_beginthread/_beginthreadex函數建立多線程

2、使用CRT的多線程函數集:兩組

采用_beginthread/_beginthreadex函數建立多線程

3、兩組函數的說明:

3.1、_beginthread和_endthread

該函數是C Runtime Library中的函數。其原型如下

unsigned long _beginthread(

void( __cdecl *start_address )( void * ),//線程函數的起始位址

unsigned stack_size,//堆棧大小,設定0為系統預設值

void *arglist );//傳遞給線程函數的參數,沒有則為NULL
           

“該函數被認為是頭腦簡單的函數”,使用該函數導緻無法有效的控制被建立線程,如不能在啟動時将該線程挂起,無法為該線程設定優先權等。另外,無法利用這個Handle來等待該線程結束等操作。該函數是早期的C Runtime Library的産物,不提倡使用,後期的改良版本為_beginthreadex。

通過_beginthread啟動的線程在應當通過調用_endthread結束,以保證清除與線程相關的資源。_endthread的原型為:

void _endthread(void);
           

3.2、_beginthreadex和_endthreadex

該函數是C Runtime Library中的一個函數,用标準C實作,相比_beginthread,_beginthreadex**對線程控制更為有力**(比前者多三個參數),是_beginthread的加強版。其原型為:

unsignedlong _beginthreadex(

void *security,//線程函數的安全描述符

unsigned stack_size,// 堆棧大小,設定0為系統預設值

unsigned ( __stdcall *start_address )( void * ),//線程函數的起始位址

void*arglist, //傳遞給線程函數的參數,沒有則為NULL

unsignedinitflag,//初始狀态,0為立即執行,CREATE_SUSPEND為建立後挂起

unsigned*thrdaddr );//指向一個32位的變量,存放線程辨別符
           

該函數傳回新線程的句柄,通過該句柄可實作對線程的控制。雖然,該函數是用标準C寫的(即可不加修改就可以移植到其他系統執行),但是由于它與Windows系統有着緊密的聯系(需要手動關閉該線程産生的Handle),是以實作時,往往需要包含windows.h。

通過_beginthreadex啟動的線程通過調用_endthreadex做相關清理。該函數比較像CreateThread函數。

_endthreadex函數的原型為:

void _endthreadex(unsigned retVal);
           

關于這兩組函數的詳細差別請參考MSDN的說明:

Creates a thread.

uintptr_t _beginthread(

   void( *start_address )( void * ),

   unsigned stack_size,

   void *arglist

);

uintptr_t _beginthreadex(

   void *security,

   unsigned stack_size,

   unsigned ( *start_address )( void * ),

   void *arglist,

   unsigned initflag,

   unsigned *thrdaddr

);
           

3.3、線程函數的定義:

_beginthread()和_beginthreadex()的線程執行函數的定義是不一樣的。

對于_beginthread()建立的線程,其線程函數定義為:

void ThreadPro(void * pArguments );
           

對于_beginthreadex()建立的線程,其線程函數定義為:

unsigned __stdcallThreadFunc( void* pArguments )
           

4、注意事項:

(1)兩者建立線程函數方式不同,_beginthreadex()的線程函數必須使用__stdcall調用方式,而且必須傳回一個unsigned型的退出碼。

(2)_beginthreadex()在建立線程失敗時傳回0,而_beginthread()在建立線程失敗時傳回-1,這一點在檢測傳回結果時必須注意。

(3)如果是調用_beginthread()建立線程,并相應地調用_endthread()結束線程時,系統将自動關閉線程句柄。而調用_beginthreadex()建立線程,并相應地調用_endthreadex()結束線程時,系統不能自動關閉線程句柄。

(4)由于_beginthread()建立線程參數比較簡單,不能控制線程的初始啟動狀态,且不傳回建立的線程句柄,也不能調用

WaitForSingleObject()/WaitForMultipleObjects()函數。是以一般不常用,而_beginthreadex()與CreatThread()函數比較相似。能友善控制線程。

注意事項:

(1) 由于_beginthread()建立的線程結束後自動關閉線程句柄,是以不能使用WaitForSingleObject()/WaitForMultipleObjects()函數來同步。

(2) 注意線程函數參數的傳遞,如果要傳遞多個參數,可以在建立線程的時候,可以将多個參數封裝為一個結構體傳遞給線程函數。

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

(1) 由于_beginthreadex()建立的線程結束後自動調用_endthreadex()函數,但是不會關閉線程句柄,是以必須手動關閉句柄,但能使用同步函數,如:

WaitForSingleObject()/WaitForMultipleObjects()函數來同步。

(2) 通過該執行個體還可以稍加改進,就可以統計5個線程的各自的工作時間,并排序。歡迎大家多多練習。

(3) 由_beginthreadex()函數建立線程,能靈和控制和管理線程,是以推薦使用該方式。