2

我搜索了 MSDN,Mutex 可以被锁定两次,但是没有关于递归在同一个线程中两次获取同一个事件对象的任何词。

我们可以在同一个线程中两次锁定 win32 事件吗?

编辑:锁定事件的含义是什么?在这里我假设事件是自动重置的。

  1. 锁定:从 WaitForXXX 唤醒线程(例如,WaitForSingleObject)
  2. Un-Lock:一个线程正在调用 SetEvent 或 PluseEvent。
4

2 回答 2

4

互斥体与事件根本不同。互斥锁用于提供互斥,因此一次只有一个线程可以访问资源,而事件只是一种通知机制。自动重置事件提供单唤醒通知,而手动重置事件提供多唤醒通知。

如果您发出自动重置事件的信号,则只有一个线程会收到该信号,并且该线程仅接收一次;任何其他线程 --- 或从同一线程对该事件的等待函数的任何其他调用 --- 将等待,直到有第二次调用SetEvent.

如果您发出手动重置事件的信号,则它会一直保持信号状态,直到您将其重置,因此可以唤醒多个线程,并且从同一线程对该事件的等待函数的多次调用将成功,直到某些线程调用为止ResetEvent

无论哪种方式,事件都没有“所有者”:仅仅因为线程 A 上次被另一个设置事件的线程从其对等待函数的调用中唤醒,没有任何东西可以阻止它再次等待,也没有任何东西可以指定线程是否如果 A 或 B 都等待相同的自动复位事件,则将唤醒 A 或 B。也没有什么需要任何特定线程调用SetEvent:系统中的任何线程都可以这样做,无论该线程是否曾经为该事件调用等待函数。实际上,一个常见的用例有一个线程调用SetEvent,而一个或多个其他线程在等待。

所以:是的,您可以等待来自刚刚等待该事件的线程的事件,但这不是锁,其他线程也可能等待该事件,并且如果事件发出信号也可能唤醒。

已编辑问题的更新:

您可以使用事件来提供锁定,但这不是固有语义的一部分。您可以使用相同的自动重置事件句柄连续调用WaitForSingleObject两次。就 Windows 而言,这不是一个错误:您只需要确保某个其他线程或多个线程调用SetEvent两次,这样等待线程就会从第一次调用唤醒到WaitForSingleObject第二次调用SetEvent发生之前,以便避免“丢失”唤醒:SetEvent不计算调用,它只是设置标志。

另外:不要使用PulseEvent. 它不能保证一个线程会唤醒,即使当前有一个线程在等待。

于 2012-04-23T08:06:36.083 回答
2

我同意安东尼·威廉姆斯的观点。

我想补充的一点是,很多人(不仅仅是你)不太了解互斥锁和自动重置事件之间的区别。它们实际上的行为相似,并且可以(从技术角度)用于资源锁定。

它们之间的主要区别在于互斥锁“知道”哪个线程拥有它。也就是说,当WaitForSingleObject(或类似的)获得互斥体时 - 它会自动“分配”给调用线程。这有两个后果:

  1. 同一个线程可以递归地获取互斥锁。当然,这不适用于自动重置事件。
  2. 如果拥有互斥锁的线程退出 - 互斥锁会自动“释放”。相应的WaitXXXX函数将返回WAIT_ABANDONED.

事件 OTOH 可以被视为信号量的特殊情况。自动重置事件相当于(最多)1 个充电的信号量,而手动重置事件 - 相当于一个无限充电的信号量。

于 2012-04-23T08:22:48.580 回答