線程的handle用處:編程
線程的handle是指向「線程的內核對象」的,而不是指向線程自己.每一個內核對象只是內核分配的一個內存塊,而且只能由內核訪問。該內存塊是一種數據結構,它的成員負責維護對象的各類信息(eg: 安全性描述,引用計數等)。安全
CloseHandle()網絡
在CreateThread成功以後會返回一個hThread的handle,且內核對象的計數加1,CloseHandle以後,引用計數減1,當變爲0時,系統刪除內核對象。數據結構
可是這個handle並不能徹底表明這個線程,它僅僅是線程的一個「標識」,系統和用戶能夠利用它對相應的線程進行必要的操縱。若是在線程成功建立後,再也不須要用到這個句柄,就能夠在建立成功後,線程退出前直接CloseHandle掉,但這並不會影響到線程的運行。異步
不執行CloseHandle() 帶來的後果:函數
若在線程執行完以後,沒有經過CloseHandle()將引用計數減1,在進程執行期間,將會形成內核對象的泄露,至關與句柄泄露,但不一樣於內存泄露, 這勢必會對系統的效率帶來必定程度上的負面影響。可是,請記住,當進程結束退出後,系統仍然會自動幫你清理這些資源。可是在這裏不推薦這種作法,畢竟不是 一個良好的編程習慣!
( 應用程序運行時,有可能泄露內核對象,可是當進程終止運行時,系統能確保全部內容均被正確地清除。另外,這個狀況是用於全部對象,資源和內存塊,也就是說,當進程終止時,系統將保證不會留下任何對象。)測試
TerminateThread()spa
函數的聲明以下:操作系統
聽過無數次不要TerminateThread,只是工做中經常使用,貌似也沒有什麼問題。今天在高強度測試中發現了一個不可原諒的錯誤。參看下面的例子.net
爲何死鎖呢?new操做符用的是小塊堆,整個進程在分配和回收內存時,都要用同一把鎖。若是一個線程在佔用該鎖時被殺死(即臨死前該線程在new或delete操做中),其餘線程就沒法再使用new或delete了,表現爲hang住。
<核心編程>裏明確提醒不要TerminateThread,但緣由並非血淋淋滴。今天發現的這個bug印證了此書的價值。
另注:許多臨時的網絡操做常常用TerminateThread,做爲網絡不通時的退出機制,之後要改改了。好比讓該線程自生自滅,自行退出。
ExitThread是推薦使用的結束一個線程的方法,當調用該函數時,當前線程的棧被釋放,而後線程終止,相對於TerminateThread函數來講,這樣作可以更好地完成附加在該線程上的DLL的清除工做
終止線程兩個函數:ExitThread() 和 TerminateThread()
若要終止線程的運行,可使用下面四種的方法:
線程函數退出循環來返回 (最佳方法 )。
經過調用ExitThread 函數,線程將自行撤消(儘可能不要使用這種方法 )。
同一個進程或另外一個進程中的線程調用TerminateThread 函數(最好避免使用這種方法 )。
該線程的主進程終止運行(避免使用 )。
下面將介紹終止線程運行的方法,而且說明線程終止運行時會出現什麼狀況。
1.線程函數返回
始終都應該將線程設計成這樣的形式,即當想要線程終止運行時,它們就可以返回。這是
確保全部線程資源被正確地清除的惟一辦法。
若是線程可以返回,就能夠確保下列事項的實現:
a) 在線程函數中建立的全部C + +對象均將經過它們的撤消函數正確地撤消。
b)操做系統將正確地釋放線程堆棧使用的內存。
c)系統將線程的退出代碼(在線程的內核對象中維護)設置爲線程函數的返回值。
d)系統將遞減線程內核對象的使用計數。
2.ExitThread 函數
可讓線程調用ExitThread 函數,以便強制線程終止運行:
該函數將終止線程的運行,並致使操做系統清除該線程使用的全部操做系統資源。可是,C++資源(如C++類對象)將不被撤消。因爲這個緣由,最好從線程函數返回,而不是經過調用ExitThread 來返回。
固然,可使用ExitThread 的dwExitThread 參數告訴系統將線程的退出代碼設置爲何。ExitThread 函數並不返回任何值,由於線程已經終止運行,不能執行更多的代碼。
注意終止線程運行的最佳方法是讓它的線程函數返回。可是,若是使用本節介紹的方法,應該知道ExitThread 函數是Windows用來撤消線程的函數。若是編寫C/C++代碼,那麼決不該該調用ExitThread 。應該使用Visual C++運行期庫函數_endthreadex。若是不使用Microsoft的Visual C++編譯器,你的編譯器供應商有它本身的ExitThread 的替代函數。無論這個替代函數是什麼,都必須使用。本章後面將說明_endthreadex的做用和它的重要性。
3.TerminateThread 函數
調用TerminateThread 函數也可以終止線程的運行:
與ExitThread 不一樣,ExitThread 老是撤消調用的線程,而TerminateThread 可以撤消任何線程。hThread參數用於標識被終止運行的線程的句柄。當線程終止運行時,它的退出代碼成爲你做爲dwExitThread 參數傳遞的值。同時,線程的內核對象的使用計數也被遞減。
注意TerminateThread 函數是異步運行的函數,也就是說,它告訴系統你想要線程終止運行,可是,當函數返回時,不能保證線程被撤消。若是須要確切地知道該線程已經終止運行,必須調用WaitForSingleObject或者相似的函數,傳遞線程的句柄。
設計良好的應用程序歷來不使用這個函數,由於被終止運行的線程收不到它被撤消的通知。線程不能正確地清除,而且不能防止本身被撤消。注意當使用返回或調用ExitThread 的方法撤消線程時,該線程的內存堆棧也被撤消。可是,若是使用TerminateThread ,那麼在擁有線程的進程終止運行以前,系統不撤消該線程的堆棧。Microsoft故意用這種方法來實現TerminateThread 。若是其餘仍然正在執行的線程要引用強制撤消的線程堆棧上的值,那麼其餘的線程就會出現訪問違規的問題。若是將已經撤消的線程的堆棧留在內存中,那麼其餘線程就能夠繼續很好地運行。此外,當線程終止運行時, DLL一般接收通知。若是使用Terminate Thread 強迫線程終止,DLL就不接收通知,這能阻止適當的清除(詳細信息參見第20章)。
4.在進程終止運行時撤消線程ExitProcess和TerminateProcess函數也能夠用來終止線程的運行。差異在於這些線程將會使終止運行的進程中的全部線程所有終止運行。另外,因爲整個進程已經被關閉,進程使用的全部資源確定已被清除。這固然包括全部線程的堆棧。這兩個函數會致使進程中的剩餘線程被強制撤消,就像從每一個剩餘的線程調用TerminateThread 同樣。顯然,這意味着正確的應用程序清除沒有發生,即C++對象撤消函數沒有被調用,數據沒有轉至磁盤等等。