何时使用AutoResetEvent和ManualResetEvent而不是Monitor.Wait()/Monitor.Pulse()?

20

它们似乎都能达到相同的目的。我在何时应选择其中之一?

4个回答

15

当您有一个线程正在等待一个或多个事件来执行某些操作时,请使用事件。

如果要限制访问数据结构的线程数量,则使用监视器。

通常,监视器保护资源,而事件告诉您发生了某些事情,例如应用程序关闭。

此外,事件可以命名(请参见OpenExisting方法),这允许它们用于跨不同进程的同步。


10

在我看来,如果可以的话最好使用 Monitor,Monitor.Wait 和 Monitor.Pulse/PulseAll 用于线程间的信号传递(Manual/AutoResetEvent 也可以),但是 Monitor 更快,并且不使用本地系统资源。而 Manual/AutoResetEvent 需要切换到内核模式并调用本地 win32 调用使用等待句柄。

有一些情况需要使用 Manual/AutoResetEvent,例如,要在进程之间进行信号传递,可以使用命名事件,还有就是在应用程序中信号本机线程。

我只是复述了我在这篇优秀文章中读到的内容。

整篇文章都值得一读,但链接将带您转到讨论事件和监视器等待/脉冲的部分。


7
当您需要线程发送或接收二进制信号而不需要关键部分时,可以使用WaitHandle。但是,Monitor.WaitMonitor.Pulse则需要关键部分。与BCL中的大多数同步机制一样,您提到的两个机制有些重叠。但是,请不要认为它们具有相同的目的。 Monitor.WaitMonitor.Pulse是比MRE或ARE更原始的同步机制。实际上,您实际上可以仅使用Monitor类来构建MRE或ARE。最重要的概念是了解Monitor.WaitWaitHandle.WaitOne方法之间的区别。WaitWaitOne都会将线程置于WaitSleepJoin状态,这意味着线程变得空闲,并且仅响应Thread.Interrupt或相应的PulseSet调用。但是,这是一个重大差异,Wait将以原子方式离开关键部分并重新获取它。WaitOne无法做到这一点。这是这些同步机制行为的根本区别,定义了它们可以使用的场景。
在大多数情况下,您将选择MRE或ARE。这些满足大多数情况下一个线程需要从另一个线程接收信号的情况。但是,如果要创建自己的信号机制,则需要使用WaitPulse。但是,.NET BCL已经涵盖了大多数流行的信号机制。以下信号机制已经存在。
手动重置事件(或ManualResetEventSlim) 自动重置事件 信号量(或SemaphoreSlim) EventWaitHandle CountdownEvent 障碍
荣誉提到BlockingCollection类。它本质上不是一种信号机制,但它具有信号机制的特性,并且可以附加数据到信号中。在这种情况下,信号表示集合中有一个项可用,与该信号关联的数据是项本身。

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接