C 執行緒的建立

2021-07-31 21:31:14 字數 3506 閱讀 1507

當使用createprocess呼叫時,系統將建立乙個程序和乙個主線程。createthread將在

主線程的基礎上建立乙個新執行緒,大致做如下步驟:

1在核心物件中分配乙個執行緒標識/控制代碼,可供管理,由createthread返回

2把執行緒

退出碼置為still_active,把執行緒掛起計數置1

3分配context結構

4分配兩頁的物理儲存以準備棧,保護頁設定為page_readwrite,第2頁設為page_guard

5lpstartaddr和lpvthread值被放在棧頂,使它們成為傳送給startofthread的引數

6把context結構的棧

指標指向棧頂(第5步)指令指標指向startofthread函式

msdn中createthread原型:

handle createthread(

lpsecurity_attributes lpthreadattributes,

dword dwstacksize,

lpthread_start_routine lpstartaddress,

lpvoid lpparameter,

dword dwcreationflags,

lpdword lpthreadid);

lpthreadattributes:指向

security_attributes

型態的結構的指標。在windows 98中忽略該引數。在windows nt中,null使用預設安全性,不可以被子執行緒繼承,否則需要定義乙個結構體將它的binherithandle成員初始化為true

dwstacksize,設定初始棧的大小,以位元組為單位,如果為0,那麼預設將使用與呼叫該函式的執行緒相同的棧空間大小。任何情況下,windows根據需要動態延長

堆疊的大小。

lpstartaddress,指向執行緒函式的

指標,形式:@函式名,函式名稱沒有限制,但是必須以下列形式宣告:

dword winapi threadproc (lpvoid lpparam) ,格式不正確將無法呼叫成功。

//也可以直接呼叫void型別

//但lpstartaddress要這樣通過lpthread_start_routine轉換如:(lpthread_start_routine)myvoid

void myvoid()

lpparameter:向執行緒函式傳遞的引數,是乙個指向結構的指標,不需傳遞引數時,為null。

dwcreationflags :執行緒標誌,可取值如下

(1)create_suspended(0x00000004):建立乙個掛起的執行緒,

(2)0:表示建立後立即啟用。

(3)stack_size_param_is_a_reservation(0x00010000):dwstacksize引數指定初始的保留堆疊的大小,否則,dwstacksize指定提交的大小。該標記值在

windows 2000/nt and windows me/98/95

上不支援。

lpthreadid:儲存新執行緒的id。

返回值:

函式成功,返回執行緒控制代碼;函式失敗返回false。

若不想返回執行緒id,設定值為null。

函式說明:

建立乙個執行緒。

語法:hthread = createthread (&security_attributes, dwstacksize, threadproc,pparam, dwflags, &idthread) ;

一般並不推薦使用 createthread函式,而推薦使用rtl 

庫里的system單元中定義的 beginthread函式,因為這除了能建立乙個執行緒和乙個入口函式以外,還增加了幾項保護措施。

在mfc程式中,應該呼叫afxbeginthread函式,在

visual c++

程式中應呼叫_beginthreadex函式。

[cpp]view plain

copy

#include 

#include "windows.h"

using

namespace

std;  

dword

winapi funproc(

lpvoid

lpparentet);  

intmain()  

dword

winapi funproc(

lpvoid

lpparentet)    

在很多參考書上,都說不要用createthread 建立執行緒、並用closehandle來關閉這個執行緒,因為這樣做會導致記憶體洩漏,而應該用_beginthread來建立執行緒,_endthread來銷毀執行緒。其實,真正的原因並非如此。看如下一段**: 執行緒

中止執行後,執行緒物件仍然在系統中,必須通過closehandle函式來關閉該執行緒物件。closehandle函式的原型是:

bool closehandle( handle hobject );//handle hobject 物件控制代碼

closehandle可以關閉多種型別的物件,比如檔案物件等,這裡使用這個函式來關閉執行緒物件。呼叫時,hobject為待關閉的執行緒物件的控制代碼。

說使用這種方法可能會引發記憶體洩漏問題,其實不完全正確。那為什麼會引起記憶體的洩漏呢?因為當執行緒的函式用到了c的標準庫的時候,很容易導致衝突,所以在建立vc的工程時,系統提示是用

單執行緒還是用多執行緒的庫,因為在c的內部有很多的

全域性變數

。例如,出錯號、

檔案控制代碼

等全域性變數。

因為在c的庫中有全域性變數,這樣用c的庫時,如果程式中使用了標準的c程式庫時,就很容易導致執行不正常,會引起很多的衝突。所以,

微軟和borland都對c的庫進行了一些改進。但是這個改進的乙個條件就是,如果乙個執行緒已經開始建立了,就應該建立乙個結構來包含這些全域性變數,接著把這些全域性變數放入執行緒的上下文中和這個執行緒相關起來。這樣,全域性變數就會依賴於這個執行緒,不會引起衝突。

這樣做就會有乙個問題,什麼時候這個執行緒開始建立呢?標準的windows的api是不知道的,因為它是靜態的庫。這些庫都是放在vc的lib的目錄內的,而執行緒函式是

作業系統

的函式。所以,vc和bc在建立執行緒時,都會用_beginthread來建立執行緒,再用_endthread來結束執行緒。這樣,它們在建立執行緒的時候,就會知道什麼時候建立了執行緒,並把全域性變數放入某一結構中,讓它和執行緒能關聯起來。這樣就不會發生衝突了。

很顯然,要完成這個功能,首先需要分配結構表把全域性變數包含起來。這個過程是在_beginthread時做的,而釋放在_endtread內完成。

所以,當用_beginthread來建立,而用closehandle來關閉執行緒時,這時複製的全域性結構就不會被釋放了,這就有了記憶體的洩漏。這就是很多資料所說的記憶體洩漏問題的真正的原因。

庫函式)。這樣就不會有什麼問題,也就不會引起衝突。例如,字串的操作函式、檔案操作等。

當某個程式建立乙個執行緒後,會產生乙個執行緒的控制代碼,執行緒的控制代碼主要用來控制整個執行緒的執行,例如停止、掛起或設定執行緒的優先順序等操作。

C 執行緒的建立

1.用乙個初始函式建立乙個執行緒 include include using namespace std void pinrtfun intmain view code 2.用類物件建立乙個執行緒 include include using namespace std class subthread...

C 建立執行緒

在window系統中編寫控制台程式,建立執行緒 使用createthread 函式建立,則執行緒函式必須申明為dword winapi 使用 beginthreadex 建立,則執行緒函式必須申明為unsigned int winapi 並需要設定環境 工程 設定 c c code generati...

c 建立執行緒

建立多引數的執行緒時,將方法要用到的引數及方法本身封裝到乙個類中,利用有參構造方法將引數的值傳入,因為方法在類內部,可以直接呼叫引數,最後用threadstart或parameterizedthreadstart委託呼叫方法。using system using system.threading n...