Windows编程--成功等待的副作用


对于有些内核对象来说,成功地调用WaitForSingleObject和WaitForMultipleObjects,实际上会改变对象的状态。成功地调用是指函数发现对象已经得到通知并且返回一个相对于WA I T _O BJECT_ 0的值。如果函数返回WAIT_TIMEOUT或WAIT_FAILED,那么调用就没有成功。如果函数调用没有成功,对象的状态就不可能改变。

当一个对象的状态改变时,我称之为成功等待的副作用。例如,有一个线程正在等待自动清除事件对象。当事件对象变为已通知状态时,函数就会发现这个情况,并将WAIT_OBJECT_0返回给调用线程。但是就在函数返回之前,该事件将被置为未通知状态,这就是成功等待的副作用。

这个副作用将用于自动清除内核对象,因为它是Microsoft为这种类型的对象定义的规则之一。其他对象拥有不同的副作用,而有些对象则根本没有任何副作用。进程和线程内核对象就根本没有任何副作用。

究竟是什么原因使得WaitForMultipleObjects函数如此有用呢,因为它能够以原子操作方式来执行它的所有操作。当一个线程调用WaitForMultipleObjects函数时,该函数能够测试所有对象的通知状态,并且能够将所有必要的副作用作为一项操作来执行。

让我们观察一个例子。两个线程以完全相同的方式来调用WaitForMultipleObjects:

 

HANDLE h[2];
h[
0] = hAutoResetEvent1; // Initially nonsignaled
h[1] = hAutoResetEvent2; // Initially nonsignaled
WaitForMultipleObjects(2, h, TRUE,INFINITE);

 

 

当WaitForMultipleObjects函数被调用时,两个事件都处于未通知状态,这就迫使两个线程都进入等待状态。然后hAutoResetEvent1对象变为已通知状态。两个线程都发现,该事件已经变为已通知状态,但是它们都无法被唤醒,因为hAutoResetEvent2仍然处于未通知状态。由于两个线程都没有等待成功,因此没有对hAutoResetEvent1对象产生任何副作用。

接着,hAutoResetEvent2变为已通知状态。这时,两个线程中的一个发现,两个对象都变为已通知状态。等待取得了成功,两个事件对象均被置为未通知状态,(等待成功后就会被重新置为未通知状态该线程变为可调度的线程。但是另一个线程的情况如何呢?它将继续等待,直到它发现两个事件对象都处于已通知状态。尽管它原先发现hAutoResetEvent1处于已通知状态,但是现在它将该对象视为未通知状态。

前面讲过,有一个重要问题必须注意,即WaitForMultipleObjects是以原子操作方式运行的。当它检查内核对象的状态时,其他任何线程都无法背着对象改变它的状态。这可以防止出现死锁情况。试想,如果一个线程看到hAutoResetEvent1已经得到通知并将事件重置为未通知状态,然后,另一个线程发现hAutoResetEvent2已经得到通知并将该事件重置为未通知状态,那么这两个线程均将被冻结:一个线程将等待另一个线程已经得到的对象,另一个线程将等待该线程已经得到的对象。WaitForMultipleObjects能够确保这种情况永远不会发生。

FangSH 2011-01-05

posted @ 2011-01-05 17:11  xyecho  阅读(474)  评论(0编辑  收藏  举报