我刚刚意识到Windows平台有SignalObjectAndWait
API函数。 但是已经有SetEvent
和WaitForSingleObject
。 您可以一起使用它们来实现与SignalObjectAndWait
相同的目标。
基于MSDN , SignalObjectAndWait
比单独调用SetEvent
和WaitForSingleObject
更高效。 它还指出:
线程可以使用
SignalObjectAndWait
函数确保工作线程在发送对象之前处于等待状态。
我不完全理解这句话,但效率并不是我们需要SignalObjectAndWait
的唯一原因。 任何人都可以提供一个场景,其中SetEvent
+ WaitForSingleObject
无法提供SignalObjectAndWait
提供的function?
我的理解是,这个单一的功能在避免以下情况下更有效率。
SignalObjectAndWait
函数提供了一种更有效的方式来发信号通知一个对象, 然后等待另一个对比单独的函数调用,比如SetEvent
然后是WaitForSingleObject
。
当你你SetEvent
和另一个[尤其是。 更高的优先级]线程正在等待这个事件,那么线程调度器可能会从控制线程中取出控制权。 当线程接收到控制WaitForSingleObject
,它唯一做的事就是下面的WaitForSingleObject
调用,从而浪费了上下文切换以实现这样一个小事情。
使用SignalObjectAndWait
你提示内核说:“嘿,我将等待另一个事件,所以如果它有什么区别,不要过度反弹,上下文切换”。
正如MSDN所解释的,目的是确保线程处于等待状态,然后事件被发送。 如果调用WaitForSingleObject,线程处于waitstate状态,但在调用SetEvent之前,不能调用SetEvent,因为只有在等待完成之后,才会发生SetEvent – 如果没有别的东西在调用SetEvent,这是毫无意义的。
正如你所知,微软给出了下面的例子,说明为什么我们可能需要SignalObjectAndWait,如果我们已经需要单独的SetEvent和WaitForSingleObject(引用微软的例子):
线程可以使用SignalObjectAndWait函数确保工作线程在发送对象之前处于等待状态。 例如,线程和工作线程可以使用事件对象的句柄来同步他们的工作。 线程执行代码如下:
dwRet = WaitForSingleObject(hEventWorkerDone, INFINITE); if( WAIT_OBJECT_0 == dwRet) SetEvent(hEventMoreWorkToDo);
工作线程执行如下代码:
dwRet = SignalObjectAndWait(hEventWorkerDone, hEventMoreWorkToDo, INFINITE, FALSE);
这个算法流程是有缺陷的,不应该被使用。 我们不需要这种线程通知对方的困惑机制,直到我们处于“竞争条件”。 在这个例子中,微软自己创建了Race Condition。 工作线程应该等待一个事件,并从列表中取出任务,而生成任务的线程应该只是向这个列表中添加任务并发信号通知事件。 所以,我们只需要一个事件,而不是像上面的Microsoft示例那样。 该名单必须由关键部分保护。 生成任务的线程不应该等待工作线程完成任务。 如果有任务需要通知某人完成,则任务应该自行发送通知。 换句话说,完成时会通知线程的任务 – 在完成处理所有任务之前,不是专门等待作业线程的线程。
像微软例子中的这样一个有缺陷的设计,为像原子SignalObjectAndWait和原子PulseEvent这样的怪物创造了迫切的需求,最终导致厄运。
这是一个算法,你怎么能达到你的目标设置在你的问题。 目标是通过简单而简单的事件来实现的,而简单的函数SetEvent和WaitForSingleObject则不需要其他函数。
重要提示:该方案纯粹基于自动重置事件。 您将永远不需要调用ResetEvent。 所有需要的函数是:SetEvent和WaitForMultipleObjects(或WaitForSingleObject)。 不需要原子事件操作。
请注意:当我写了一个线程睡眠,它不会调用“睡眠”API调用 – 它不会被需要,它只是因为调用WaitForMultipleObjects(或WaitForSingleObject)在“等待”状态。
如您所知,自动重置事件,SetEvent和WaitForMultipleObjects函数非常可靠。 他们自NT 3.1以来就存在了。 你总是可以设计出一个完全依赖于这些简单函数的程序逻辑 – 所以你永远不需要假定像PulseEvent或SignalObjectAndWait这样的原子操作的复杂和不可靠的函数。 顺便说一句,SignalObjectAndWait只出现在Windows NT 4.0中,而SetEvent和WaitForMultipleObjects确实存在于最初版本的Win32 – NT 3.1中。