第六章 線程基本概念
1.線程的組成
(1)線程內核對象:用于管理線程及存儲線程的統(tǒng)計信息
(2)線程棧:維護線程執(zhí)行時需要的函數(shù)參數(shù)和局部變量?!【€程棧所需的內存是從進程中分配而得的,其大小默認是1M.
每個線程都有自已獨立的線程棧。
進程不執(zhí)行任何代碼,所有的代碼都是由線程執(zhí)行的。進程相當于一個裝載線程的容器。
線程共享進程的地址空間和數(shù)據(jù),如內核對象句柄(內核對象句柄只能依附于某個進程而不是某個線程)
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)會對線程函數(shù)內創(chuàng)建的所有對象調用析構函數(shù)。
2.ExitThread(). 線程退出, 系統(tǒng)會清理線程棧。 但是系統(tǒng)不會對線程函數(shù)內創(chuàng)建的所有對象調用析構函數(shù)。
3.TerminateThread().線程異步退出,系統(tǒng)不清理線程棧。只到擁有該線程的進程退出時才清理線程棧。
該函數(shù)是個異步函數(shù),它只會告訴系統(tǒng)去殺掉某個線程,但是系統(tǒng)不會保證當該函數(shù)返回時線程立刻終止。
因此我們如果我們要確認線程已經(jīng)終止了,則需要用WaitForSingleObject()來等待線程結束。
4.內核對象由進程所擁有,用戶對象由線程擁有。線程可擁有兩種用戶對象:Windows和Hook.
5.線程終止后,線程所擁有的用戶對象會被系統(tǒng)釋放。
6.GetExitCodeThread() //檢查線程是否已終止
4.線程內部細節(jié)
1.CreateThread 和 _beginthreadex 區(qū)別:
CreateThread是系統(tǒng)API,_beginthreadex是CRT(C Run Time Library 運行時庫)函數(shù). _beginthreadex內部會調用CreateThread函數(shù)。
_endthreadex會釋放_beginthreadex為tiddata結構分配的內存。
如果線程函數(shù)中調用了CRT函數(shù)(注:不是全部CRT函數(shù) 只是其中一部分函數(shù)),則該線程函數(shù)必須由_beginthreadex而不是CreateThread函數(shù)創(chuàng)建。否則會產生內存泄露。
如果在除主線程之外的任何線程中進行一下操作,你就應該使用多線程版本的C runtime library,并使用_beginthreadex和_endthreadex:
(1) 使用malloc()和free(),或是new和delete
(2) 使用stdio.h或io.h里面聲明的任何函數(shù)
(3) 使用浮點變量或浮點運算函數(shù)
(4) 調用任何一個使用了靜態(tài)緩沖區(qū)的runtime函數(shù),比如:asctime(),strtok()或rand()
2._beginthreadex和_beginthread區(qū)別
_beginthreadex內部會自動調用 _endthreadex.
_beginthread內部會自動調用_endthread.
_endthread內部會自動調用CloseHandle關閉當前Thread內核對象的句柄,所以在用_beginthread 時我們不需要在主線程中調用CloseHandle來關閉子線程的句柄。
_endthreadex相比_endthread而言更安全。它不會自動關閉當前Thread內核對象的句柄。所以在用_beginthreadex時我們需要用CloseHandle來關閉子線程的句柄。
5.偽句柄和真實句柄
1.偽句柄(Pseudohandle):
HANDLE GetCurrentProcess();
HANDLE GetCurrentThread();
以上兩個函數(shù)會返回指向線程或進程內核對象的偽句柄(其實以上兩個函數(shù)返回的是一個常數(shù)如-1)。所以偽句柄的值永遠是指向當前線程或進程的。
如果把該值傳給子進程,該值則代表當前子進程的偽句柄。所以把句柄傳給子線程時一定要傳真時的句柄不能傳偽句柄。
該句柄不會增加內核對象的引用計數(shù),所以不需要調用CloseHandle()函數(shù)。
2.把偽句柄轉換成真實句柄
DuplicateHandle會增加內核對象的引用計數(shù),所以要用CloseHandle()來關閉復制所得的對象句柄。
6.Common API
DWORD GetCurrentProcessId();
DWORD GetCurrentThreadId();
HANDLE GetCurrentProcess();
HANDLE GetCurrentThread();
DuplicateHandle()