AutoResetEvent,ManualResetEvent vs Monitor

时间:2009-11-11 18:31:54

标签: .net concurrency synchronization .net-3.5

假设我必须在.Net 3.5 SP1中编排同步算法,并且标题中列出的任何同步原语都完全适合该任务。

从绩效的角度来看,其中任何一个都比其他人更有效吗?

我问这个是因为我现在已经编码了一段时间,但是没有正确的知识。

3 个答案:

答案 0 :(得分:19)

WaitHandles看起来与Wait / Pulse Constructs非常相似,但不同之处在于:即使没有线程在等待,WaitHandles Set方法也会设置Signal。这意味着如果您在一个线程中调用Set然后在同一个waithandle上的另一个线程中调用WaitOne,则第二个线程将继续。 Wait和Pulse不同,Pulse仅发出已在等待队列中的线程的信号。这意味着如果你在一个线程中调用Pulse然后在同一个对象上的另一个线程中调用Wait,则第二个线程将永远等待(死锁)。如果使用Wait and Pulse,你必须非常小心,只有在你知道自己在做什么的情况下才使用它,否则你可能会很幸运 ......

要使用Monitor,天气AutoReset或ManualReset自己创建WaitHandle的行为,您必须做的不仅仅是简单的等待/脉冲构造。 只需使用您完成工作所需的工具

如果无法使用简单的锁定或原子操作同步线程,请考虑使用WaitHandles。如果无法使用WaitHandles同步线程,请考虑使用Wait和Pulse。

答案 1 :(得分:4)

如果可以,请使用Monitor。它类似于CRITICAL_SECTION。 AutoResetEvent / ManualResetEvent可能会有更多的开销,因为这些可以由不同的进程共享,而Monitor属于单个进程。

答案 2 :(得分:2)

如果您遵循一些简单的规则,等待和脉冲就可以了:

  1. 如果您的物品不需要锁定,您可能无法锁定,您可以提前告知它已准备就绪;但是,如果它看起来你必须等待,你必须获得锁定,然后确保你真的必须等到实际执行之前;在大多数情况下,你也应该假设你可以随意醒来,无论条件是否准备就绪,所以你应该每次醒来时重新检查条件,并在需要时重新等待。
  2. 在条件设置完成后,必须给出脉冲,以便等待代码继续。
  3. 如果您有类似“退出”标志的东西,在释放锁定后,让获取锁定的每个代码片段测试退出标志可能会有所帮助,如果设置标志,重新获取锁定并发送脉冲。然后你可以让一个退出例程设置标志,尝试获取零超时锁定,并仅在可以获取锁定时发送脉冲。如果采集失败,您可以放心,其他一些代码将发送必要的脉冲。这将避免“退出”例程陷入锁定的任何可能性。