我有一个应用程序,其中多个线程在同一事件对象上等待发信号.我看到的问题似乎是一种竞争条件,因为有时某些线程的等待状态(WaitForMultipleObjects)由于事件信号而返回,而其他线程的等待状态显然看不到事件信号,因为它们不是回来.这些事件是使用CreateEvent创建的手动重置事件对象.
我的应用程序处理这些事件,以便在发出事件对象信号时,其“所有者”线程负责重置事件对象的信号状态,如下面的代码片段所示.等待同一事件的其他线程不会尝试重置其信号状态.
switch ( dwObjectWaitState = ::WaitForMultipleObjects( i, pHandles, FALSE, INFINITE ) )
{
case WAIT_OBJECT_0 + BAS_MESSAGE_READY_EVT_ID:
::ResetEvent( pHandles[BAS_MESSAGE_READY_EVT_ID] );
/* handles the event */
break;
}
换句话说,我看到的问题似乎是Remarks section for PulseEvent
on the MSDN website中描述的问题:
If the call to PulseEvent occurs
during the time when the thread has
been removed from the wait state, the
thread will not be released because
PulseEvent releases only those threads
that are waiting at the moment it is
called. Therefore, PulseEvent is
unreliable and should not be used by
new applications. Instead, use
condition variables.
如果这是正在发生的事情,我能看到的唯一解决方案是每个线程使用该对象的所有者线程注册其对给定事件对象的使用,以便所有者线程可以确定何时可以安全地重置事件对象的信号状态.
有一个更好的方法吗?谢谢.
最佳答案 在PulseEvent描述中使用条件变量.唯一的问题是Windows上的本机条件变量是从Vista开始实现的,因此像XP这样的旧系统没有它.但你可以使用其他一些同步对象模拟条件变量(
http://www1.cse.wustl.edu/~schmidt/win32-cv-1.html),但我认为最简单的方法是使用boost库中的条件变量及其notify_all方法来唤醒所有线程(
http://www.boost.org/doc/libs/1_41_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref)
另一种可能性(但不是很漂亮)是为每个线程创建一个事件,现在你有了PulseEvent,你可以为所有线程调用SetEvent.对于此解决方案,可能自动重置事件会更好.