【问题标题】:Is Win32 Event object recursive mutexes?Win32 事件对象是递归互斥锁吗?
【发布时间】:2012-04-23 07:50:17
【问题描述】:

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

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

编辑:Lock事件是什么意思?这里我假设事件是自动重置的。

  1. 锁定:线程从 WaitForXXX 唤醒(例如,WaitForSingleObject)
  2. 解锁:线程正在调用 SetEvent 或 PluseEvent。

【问题讨论】:

  • Win32 事件不能被“锁定”。一个互斥体可以被锁定两次是什么意思?

标签: windows multithreading locking mutex deadlock


【解决方案1】:

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

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

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

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

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

已编辑问题的更新:

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-29
      • 1970-01-01
      • 2010-12-07
      • 1970-01-01
      相关资源
      最近更新 更多