採用_beginthread/_beginthreadex函數創建多線程

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

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

這裏寫圖片描述

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

這裏寫圖片描述

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()函數創建線程,能靈和控制和管理線程,所以推薦使用該方式。

發佈了98 篇原創文章 · 獲贊 68 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章