windows 多線程之終結線程

許多人可能不太重視線程的終止。其實線程終止需要完成得事情很多,合理運用能發揮很大的作用。首先講一下終止的方法。

1、”壽終正寢“(正常終止,相應的線程函數返回,如我在CreateThread寫的那樣,這是最好的方法,相應資源會被釋放)

2、“自殺”(調用ExitThread,【【VOID ExitThread(DWORD dwExitCode)】】,不被推薦,因爲這樣雖然可以講操作系統分配的資源回收,卻不會將自己聲明的c/c++資源回收(比如類對象依舊存在)

3、“他殺”(TerminateThread,【【BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode)】】,不推薦)

4、”殉情“(支持線程的進程結束,不推薦)

不管採用哪種方法,當線程終止的時候,

1、該線程擁有的所有用戶級別對象句柄都被釋放,退出碼從STILL_ACTIVE變爲了傳給相應參數的的dxExitCode的值。

2、很重要的一點是,當終止時,線程的核對象(kernel object,可以理解爲操作系統用來記錄該線程信息的對象)會變成signaled(在後面的信號量等地方會用到,請牢記這一點!!)

3、如果該線程是相應進程中的最後一個,操作系統也會認爲進程結束了

4、線程的kernel object的使用量(usage count)會減少1

下面是代碼:

#include <Windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI FirstThread(PVOID pvParam){
*(int*)pvParam=5;
ExitThread(1);
return(0);
}
int main(){
int x;
DWORD dwThreadId;
DWORD exitCode;
HANDLE hThread=CreateThread(NULL,0,FirstThread,&x,0,&dwThreadId);


GetExitCodeThread(hThread,&exitCode);
cout<<"thread exitcode1:"<<exitCode<<endl;


HANDLE hCurrentProcess=GetCurrentProcess();
cout<<"Created Thread ID"<<dwThreadId<<endl<<"Thread Handle:"<<hThread<<endl<<"Current Process Handle is :"<<hCurrentProcess<<endl;
Sleep(200);
GetExitCodeThread(hThread,&exitCode);
cout<<"thread exitcode2:"<<exitCode<<endl;


hThread=CreateThread(NULL,0,FirstThread,&x,0,&dwThreadId);
TerminateThread(hThread,3);
Sleep(200);
GetExitCodeThread(hThread,&exitCode);
cout<<"thread exitcode3:"<<exitCode<<endl;


CloseHandle(hThread);


system("pause");
return 0;
}

最後的輸出如下:



259正是STILL_ACTIVE的宏定義(0x00000103L)

這裏可能會對sleep的使用有疑問,那麼您可以去掉兩個sleep試一下,看看結果有什麼區別(最好是自己寫一下,這樣纔會有更好地理解)。

我的理解是線程調用create之後不會立馬執行到我們自定義的線程函數,而是還有一些操作系統的初始化工作。這時候主線程(即main函數還會繼續執行下去,而這時候的線程狀態已經標記爲STILL_ACTIVE了,所以纔會出現上面的情況。爲了驗證猜想我有編寫了下面的程序:

#include <Windows.h>
#include <iostream>
using namespace std;
LARGE_INTEGER Counter1,Counter2,Counter3;
double GetTimeEps(LARGE_INTEGER& count1,LARGE_INTEGER& count2){
LARGE_INTEGER CPUFrequency;
QueryPerformanceFrequency(&CPUFrequency);
double d=(double)(count1.QuadPart-count2.QuadPart)/(double)CPUFrequency.QuadPart*1000.0;
return d;
}


DWORD WINAPI FirstThread(PVOID pvParam){
QueryPerformanceCounter(&Counter3);
cout<<"time interval to mythreadfunction is:"<<GetTimeEps(Counter3,Counter1)<<endl;
*(int*)pvParam=5;
ExitThread(1);
return(0);
}
int main(){
int x;
BOOL bResult=0;
DWORD dwThreadId;
DWORD exitCode;


QueryPerformanceCounter(&Counter1);
HANDLE hThread=CreateThread(NULL,0,FirstThread,&x,0,&dwThreadId);


GetExitCodeThread(hThread,&exitCode);
cout<<"thread exitcode1:"<<exitCode<<endl;
QueryPerformanceCounter(&Counter2);
cout<<"time interval to cout is:"<<GetTimeEps(Counter2,Counter1)<<endl;




HANDLE hCurrentProcess=GetCurrentProcess();
cout<<"Created Thread ID"<<dwThreadId<<endl<<"Thread Handle:"<<hThread<<endl<<"Current Process Handle is :"<<hCurrentProcess<<endl;
Sleep(200);
GetExitCodeThread(hThread,&exitCode);
cout<<"thread exitcode2:"<<exitCode<<endl;


hThread=CreateThread(NULL,0,FirstThread,&x,0,&dwThreadId);
TerminateThread(hThread,3);
Sleep(200);
GetExitCodeThread(hThread,&exitCode);
cout<<"thread exitcode3:"<<exitCode<<endl;






CloseHandle(hThread);


system("pause");
return 0;
}

最後程序的結果如下:


可以很清楚的看到在真正進入我們自定義的線程函數之前有“很長”(相對於線程來說)的時間來進行操作系統方面的初始化工作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章