PulseEvent这是将释放一个(如果启用了手动重置,多个)正在等待事件对象的线程,并将事件对象设置为“未设置”状态的API。如果此时恰好没有线程在等待这个事件,那么除了设置为“未设置”状态之外,事件什么也不会发生。但它的缺陷就在于此。你怎么知道你认为正在等待事件的线程一定是“真的(正在等待)”?显然我们不能使用下面的方法:因为在上面的代码中,触发信号和等待事件这两个操作存在竞争条件。由信号对象触发的线程可能已经完成了所有工作,将在您等待事件对象之前触发一个脉冲事件(PulseEvent)。您可以尝试使用SignalObjectAndWait这个函数,它将信号触发和等待合并为一个操作。但即便如此,您也无法确定在脉冲发生时线程是否正在等待事件。当线程等待事件时,设备驱动程序或内核本身的一部分可能会借用线程来执行某些任务处理(通过内核模式APC)。在此期间,线程没有等待,因为设备驱动程序正在使用它。如果线程在借用时发生PulseEvent,则不会从等待中唤醒,因为PulseEvent函数只会唤醒PulseEvent发生时正在等待的线程。用户模式程序不仅不能阻止内核模式代码对用户模式程序线程执行此操作,而且也无法检测它是否已经发生。(您可能会看到这种情况发生的一个地方是,如果您将调试器附加到进程,因为调试器会执行诸如挂起和恢复线程之类的操作,这会导致内核APC。)因此,PulseEvent函数是无用的,应该避免使用。它继续存在只是为了向后兼容。附加信息:与内核APC相关的整个业务还意味着当您触发信号量、自动重置事件或其他在发出信号时释放单个线程的同步对象时,您无法预测哪个线程将被唤醒。如果一个线程被“借”来为内核APC服务,当它返回到等待列表时,它会“回到行尾”。因此,等待内核对象的对象的顺序是不可预测的并且不能被依赖。综上所述,请老老实实使用SetEvent/ResetEvent,简单实用!最后,RaymondChen的《The Old New Thing》是我最喜欢的博客之一。它包含了很多关于Windows的小知识。对于Windows平台的开发者来说真的非常有用。有帮助。本文来自:《PulseEvent is fundamentally flawed》
