線程基本概念
1.線程的組成
(1)線程內(nèi)核對(duì)象:用于管理線程及存儲(chǔ)線程的統(tǒng)計(jì)信息
(2)線程棧:維護(hù)線程執(zhí)行時(shí)需要的函數(shù)參數(shù)和局部變量?!【€程棧所需的內(nèi)存是從進(jìn)程中分配而得的,其大小默認(rèn)是1M.
每個(gè)線程都有自已獨(dú)立的線程棧。
進(jìn)程不執(zhí)行任何代碼,所有的代碼都是由線程執(zhí)行的。進(jìn)程相當(dāng)于一個(gè)裝載線程的容器。
線程共享進(jìn)程的地址空間和數(shù)據(jù),如內(nèi)核對(duì)象句柄(內(nèi)核對(duì)象句柄只能依附于某個(gè)進(jìn)程而不是某個(gè)線程)
2.線程函數(shù)原型
DWORD WINAPI ThreadFunc(PVOID pvParam)
{
DWORD dwResult = 0;
...
return(dwResult);
}
The system allocates memory out of the process' address space for use by the thread's stack.
3.終止線程
1.線程正常退出。系統(tǒng)會(huì)對(duì)線程函數(shù)內(nèi)創(chuàng)建的所有對(duì)象調(diào)用析構(gòu)函數(shù)。
2.ExitThread(). 線程退出, 系統(tǒng)會(huì)清理線程棧。 但是系統(tǒng)不會(huì)對(duì)線程函數(shù)內(nèi)創(chuàng)建的所有對(duì)象調(diào)用析構(gòu)函數(shù)。
3.TerminateThread().線程異步退出,系統(tǒng)不清理線程棧。只到擁有該線程的進(jìn)程退出時(shí)才清理線程棧。
該函數(shù)是個(gè)異步函數(shù),它只會(huì)告訴系統(tǒng)去殺掉某個(gè)線程,但是系統(tǒng)不會(huì)保證當(dāng)該函數(shù)返回時(shí)線程立刻終止。
因此我們?nèi)绻覀円_認(rèn)線程已經(jīng)終止了,則需要用WaitForSingleObject()來(lái)等待線程結(jié)束。
4.內(nèi)核對(duì)象由進(jìn)程所擁有,用戶對(duì)象由線程擁有。線程可擁有兩種用戶對(duì)象:Windows和Hook.
5.線程終止后,線程所擁有的用戶對(duì)象會(huì)被系統(tǒng)釋放。
6.GetExitCodeThread() //檢查線程是否已終止
4.線程內(nèi)部細(xì)節(jié)
1.CreateThread 和 _beginthreadex 區(qū)別:
CreateThread是系統(tǒng)API,_beginthreadex是CRT(C Run Time Library 運(yùn)行時(shí)庫(kù))函數(shù). _beginthreadex內(nèi)部會(huì)調(diào)用CreateThread函數(shù)。
_endthreadex會(huì)釋放_beginthreadex為tiddata結(jié)構(gòu)分配的內(nèi)存。
如果線程函數(shù)中調(diào)用了CRT函數(shù)(注:不是全部CRT函數(shù) 只是其中一部分函數(shù)),則該線程函數(shù)必須由_beginthreadex而不是CreateThread函數(shù)創(chuàng)建。否則會(huì)產(chǎn)生內(nèi)存泄露。
如果在除主線程之外的任何線程中進(jìn)行一下操作,你就應(yīng)該使用多線程版本的C runtime library,并使用_beginthreadex和_endthreadex:
(1) 使用malloc()和free(),或是new和delete
(2) 使用stdio.h或io.h里面聲明的任何函數(shù)
(3) 使用浮點(diǎn)變量或浮點(diǎn)運(yùn)算函數(shù)
(4) 調(diào)用任何一個(gè)使用了靜態(tài)緩沖區(qū)的runtime函數(shù),比如:asctime(),strtok()或rand()
2._beginthreadex和_beginthread區(qū)別
_beginthreadex內(nèi)部會(huì)自動(dòng)調(diào)用 _endthreadex.
_beginthread內(nèi)部會(huì)自動(dòng)調(diào)用_endthread.
_endthread內(nèi)部會(huì)自動(dòng)調(diào)用CloseHandle關(guān)閉當(dāng)前Thread內(nèi)核對(duì)象的句柄,所以在用_beginthread 時(shí)我們不需要在主線程中調(diào)用CloseHandle來(lái)關(guān)閉子線程的句柄。
_endthreadex相比_endthread而言更安全。它不會(huì)自動(dòng)關(guān)閉當(dāng)前Thread內(nèi)核對(duì)象的句柄。所以在用_beginthreadex時(shí)我們需要用CloseHandle來(lái)關(guān)閉子線程的句柄。
5.偽句柄和真實(shí)句柄
1.偽句柄(Pseudohandle):
HANDLE GetCurrentProcess();
HANDLE GetCurrentThread();
以上兩個(gè)函數(shù)會(huì)返回指向線程或進(jìn)程內(nèi)核對(duì)象的偽句柄(其實(shí)以上兩個(gè)函數(shù)返回的是一個(gè)常數(shù)如-1)。所以偽句柄的值永遠(yuǎn)是指向當(dāng)前線程或進(jìn)程的。
如果把該值傳給子進(jìn)程,該值則代表當(dāng)前子進(jìn)程的偽句柄。所以把句柄傳給子線程時(shí)一定要傳真時(shí)的句柄不能傳偽句柄。
該句柄不會(huì)增加內(nèi)核對(duì)象的引用計(jì)數(shù),所以不需要調(diào)用CloseHandle()函數(shù)。
2.把偽句柄轉(zhuǎn)換成真實(shí)句柄
DuplicateHandle會(huì)增加內(nèi)核對(duì)象的引用計(jì)數(shù),所以要用CloseHandle()來(lái)關(guān)閉復(fù)制所得的對(duì)象句柄。
6.Common API
DWORD GetCurrentProcessId();
DWORD GetCurrentThreadId();
HANDLE GetCurrentProcess();
HANDLE GetCurrentThread();
DuplicateHandle()
posted on 2010-04-20 18:12
李陽(yáng) 閱讀(1355)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
C++