TerminateThread 與 該線程創建的內核對象 無關

本文旨在說明內核對象與TerminateThread 的無關性。


A. 問題:
強制結束一個線程後. 該線程佔有的鎖會不會釋放?
那一個線程正在阻塞(比如正在sleep()). 該怎麼結束它呢?


B.1. 存在的理論1:
Te r m i n a t e T h r e a d 能夠撤消任何線程。
h T h r e a d 參數用於標識被終止運行的線程的句柄。當線程終止運行時,它的退出代碼成爲你作
爲d w E x i t C o d e 參數傳遞的值。同時,線程的內核對象的使用計數也被遞減。

B.2. 存在的理論2:
TerminateThread,內核對象應該不會被撤銷只是收到通知,改對象的狀態爲“已通知”
一個線程擁有兩個用戶對象,即窗口和掛鉤。當線程終止運行時,系統會自動撤消任何窗口,並且卸載線程創建的或安裝的任何掛鉤。其他對象只有在擁有線程的進程終止運行時才被撤消。
當一個線程終止運行時,在與它相關聯的線程內核對象的所有未結束的引用關閉之前,該內核對象不會自動被釋放。
線程內核對象的使用計數遞減1

B.3. 存在的理論3:

 9.6.1 釋放問題
互斥對象不同於所有其他內核對象,因爲互斥對象有一個“線程所有權”的概念。本章介
紹的其他內核對象中,沒有一種對象能夠記住哪個線程成功地等待到該對象,只有互斥對象能
夠對此保持跟蹤。互斥對象的線程所有權概念是互斥對象爲什麼會擁有特殊異常規則的原因,
這個異常規則使得線程能夠獲取該互斥對象,儘管它沒有發出通知。
這個異常規則不僅適用於試圖獲取互斥對象的線程,而且適用於試圖釋放互斥對象的線程。
當一個線程調用R e l e a s e M u t e x 函數時,該函數要查看調用線程的I D 是否與互斥對象中的線程I D
相匹配。如果兩個I D 相匹配,遞歸計數器就會像前面介紹的那樣遞減。如果兩個線程的I D 不匹
配,那麼R e l e a s e M u t e x 函數將不進行任何操作,而是將FA L S E (表示失敗)返回給調用者。此
時調用G e t L a s t E r r o r ,將返回E R R O R _ N O T _ O W N E R (試圖釋放不是調用者擁有的互斥對象)。
因此,如果在釋放互斥對象之前,擁有互斥對象的線程終止運行(使用E x i t T h r e a d 、
Te r m i n a t e T h r e a d 、E x i t P r o c e s s 或Te r m i n a t e P r o c e s s 函數),那麼互斥對象和正在等待互斥對象的
其他線程將會發生什麼情況呢?答案是,系統將把該互斥對象視爲已經被放棄——擁有互斥對
象的線程決不會釋放它,因爲該線程已經終止運行。
由於系統保持對所有互斥對象和線程內核對象的跟蹤,因此它能準確的知道互斥對象何時
被放棄。當一個互斥對象被放棄時,系統將自動把互斥對象的I D 復置爲0 ,並將它的遞歸計數
器復置爲0 。然後,系統要查看目前是否有任何線程正在等待該互斥對象。如果有,系統將
“公平地”選定一個等待線程,將I D 設置爲選定的線程的I D ,並將遞歸計數器設置爲1 ,同時,
選定的線程變爲可調度線程。
這與前面的情況相同,差別在於等待函數並不將通常的WA I T _ O B J E C T _ 0 值返回給線程。
相反,等待函數返回的是特殊的WA I T _ A B A N D O N E D 值。這個特殊的返回值(它只適用於互
斥對象)用於指明線程正在等待的互斥對象是由另一個線程擁有的,而這另一個線程已經在它
完成對共享資源的使用前終止運行。這不是可以進入的最佳情況。新調度的線程不知道目前資
源處於何種狀態,也許該資源已經完全被破壞了。在這種情況下必須自己決定應用程序應該怎
麼辦。在實際運行環境中,大多數應用程序從不明確檢查WA I T _ A B A N D O N E D 返回值,因爲線
程很少是剛剛終止運行(上面介紹的情況提供了另一個例子,說明爲什麼決不應該調用Te r m i n a t e T h r e a d 函數)。


C. 根據理論,我覺得:
所以線程結束後,內核對象還是可以使用的。
另外不管使用什麼資源,以及線/進程所處狀態,除了在內核模式中或者調試中,否則都可以使用Terminate
如果使用Terminate,進程應該不會釋放對象。

 

 

阿呆 14:15:09
至於你說的,已經鎖定的 mutex 是否已經解鎖? 但我想應該不會。
我前面回答的也是不會。
阿呆 14:15:24
當然我知道,根據理論上說,會收到通知。
阿呆 14:15:45
所以這一點只能做測試實例測試。

 

下面我作了對Event 的測試,因爲我不清楚Mutex 何爲解鎖 ?

 

測試結果:
1. EVENT內核對象被線程A創建,並更改狀態。
2. TerminateThread 線程A
3. EVENT內核對象  沒有被清除,狀態也沒有還原。
4. 使用WaitForSingleObject 最少1 次後,EVENT內核對象狀態可能自動還原,要看創建時的參數

5. 補充:線程A 並不是被TerminateThread結束,而是正常結束,同樣:EVENT內核對象  沒有被清除,狀態也沒有還原。

 

部分測試代碼:
 pDlg->m_hEvent = ::CreateEvent( NULL, TRUE, TRUE, "TEST" );
或者是:pDlg->m_hEvent = ::CreateEvent( NULL, FALSE, TRUE, "TEST" );
參考MSDN:
bManualReset
[in] If this parameter is TRUE, the function creates a manual-reset event object which requires use of the ResetEvent function set the state to nonsignaled. If this parameter is FALSE, the function creates an auto-reset event object, and system automatically resets the state to nonsignaled after a single waiting thread has been released.

 

檢查hEvent的測試代碼:

 HANDLE hEvent = ::OpenEvent( EVENT_ALL_ACCESS, FALSE, "TEST" );
 
if!hEvent )
 
{
  MessageBox( 
"Event doesn't existing." );
  
return;
 }


 DWORD dwRet 
= ::WaitForSingleObject( hEvent, 1000 );
 
if( WAIT_TIMEOUT == dwRet )
 
{
  MessageBox( 
"Event is nonsignaled" );
 }

 
else
 
{
  MessageBox( 
"Event is signaled" );
 }

 

關於EVENT 內核對象, 我經過測試確定:

1. Event is nonsignaled  是EVENT 內核對象的最初狀態。
   我在創建時已經設置爲:signaled
2. 線程強制結束後,event內核對象沒有改變並存在。

 


測試代碼: vc6 win2k

 TestTerminateThread.zip (21.7KB)

 

VC技術羣:30107096

發佈了60 篇原創文章 · 獲贊 2 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章