互斥对象详记


 互斥对象的行为特性与关键代码段相同,但是互斥对象属于内核对象,而关键代码段则属于用户方式对象。这意味着互斥对象的运行速度比关键代码段要慢。但是这也意味着不同进程中的多个线程能够访问单个互斥对象,并且这意味着线程在等待访问资源时可以设定一个超时值

I D用于标识系统中的哪个线程当前拥有互斥对象(互斥对象的特殊点

互斥对象的使用规则如下:

• 如果线程I D是0(这是个无效I D),互斥对象不被任何线程所拥有,并且发出该互斥对象的通知信号。

• 如果I D是个非0数字,那么 这个ID的线程就拥有互斥对象,并且不发出该互斥对象的通知信号。

对于互斥对象来说,正常的内核对象的已通知和未通知规则存在一个特殊的异常情况。比如说,一个线程试图wait一个未通知的互斥对象。在这种情况下,该线程通常被置于等待状态。然而,系统要查看试图获取互斥对象的线程的I D是否与互斥对象中记录的线程I D相同。如果两个线程I D相同,即使互斥对象处于未通知状态,系统也允许该线程保持可调度状态。我们不认为该“异常”行为特性适用于系统中的任何地方的其他内核对象。每当线程成功地等待互斥对象时,该对象的递归计数器就递增。若要使递归计数器的值大于1,唯一的方法是线程多次等待相同的互斥对象,以便利用这个异常规则

简单点说,上面的规则就是:在一个线程中,你可以任意多次wait,

DWORD WINAPI ThreadFunc1(PVOID pvParam) 
{
	int nReturn = WaitForSingleObject(hEvent,INFINITE) ;
	TRACE1("wait1 nReturn:%d\n",nReturn) ;
    nReturn = WaitForSingleObject(hEvent,INFINITE) ;
	TRACE1("wait1 nReturn:%d\n",nReturn) ;
	TRACE("wait1 sucess\n") ; 
	ReleaseMutex(hEvent) ;
	ReleaseMutex(hEvent) ;
	return(0);
}

这是会成功的,第二次wait,系统会比较线程ID,如果两个线程I D相同,即使互斥对象处于未通知状态,系统也允许该线程保持可调度状态,也就是第二次wait同样返回WA I T _ O B J E C T _ 0。

当目前拥有对资源的访问权的线程不再需要它的访问权时,它必须调用R e l e a s e M u t e x函数来释放该互斥对象。

该函数将对象的递归计数器递减1。如果线程多次成功地等待一个互斥对象,在互斥对象的递归计数器变成0之前,该线程必须以同样的次数调用R e l e a s e M u t e x函数。当递归计数器到达0时,该线程I D也被置为0,同时该对象变为已通知状态。

释放问题:

其他内核对象中,没有一种对象能够记住哪个线程成功地等待到该对象,只有互斥对象能够对此保持跟踪(通过线程ID),这个异常规则使得线程能够获取该互斥对象,尽管它没有发出通知。

这个异常规则不仅适用于试图获取互斥对象的线程,而且适用于试图释放互斥对象的线程。当一个线程调用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,会立刻执行这个操作,因为ID是可复用的,我尝试过在拥有互斥对象的线程终止运行后,立刻创建一个相同ID的线程,结果发现互斥对象已处于通知状态,这种状态下,其他等待中的线程中wait成功后返回的并不是WA I T _ O B J E C T _ 0。相反,wait返回的是特殊的WA I T _ A B A N D O N E D值。这个特殊的返回值(它只适用于互斥对象)用于指明线程正在等待的互斥对象是由另一个线程拥有的,而这另一个线程已经在它完成对共享资源的使用前终止运行(测试过,只要没调用对应的数目(和wait数目对应)的ReleaseMutex,无论线程是否正常终止,都返回WA I T _ A B A N D O N E D).

原文地址:https://www.cnblogs.com/hgy413/p/3693625.html