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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值