.net 自动复位事件、手动复位事件与监视器
假设我必须在.NET3.5SP1中协调一个同步算法,标题中列出的任何同步原语都非常适合该任务 从性能的角度来看,其中有哪一个比其他的性能更好.net 自动复位事件、手动复位事件与监视器,.net,concurrency,synchronization,.net-3.5,.net,Concurrency,Synchronization,.net 3.5,假设我必须在.NET3.5SP1中协调一个同步算法,标题中列出的任何同步原语都非常适合该任务 从性能的角度来看,其中有哪一个比其他的性能更好 我问这个问题是因为我已经编写了一段时间了,但对这个主题没有适当的了解。如果可以,请使用Monitor。它类似于一个关键部分。AutoResetEvent/ManualResetEvent的开销可能稍大一些,因为它们可以由不同的进程共享,而监视器属于单个进程。WaitHandles看起来与Wait/Pulse构造非常相似,但区别在于细节:WaitHandle
我问这个问题是因为我已经编写了一段时间了,但对这个主题没有适当的了解。如果可以,请使用Monitor。它类似于一个关键部分。AutoResetEvent/ManualResetEvent的开销可能稍大一些,因为它们可以由不同的进程共享,而监视器属于单个进程。WaitHandles看起来与Wait/Pulse构造非常相似,但区别在于细节:WaitHandles Set方法即使没有线程在等待,也会设置信号。这意味着如果在一个线程中调用Set,然后在同一个waithandle上的另一个线程中调用WaitOne,第二个线程将继续。Wait和Pulse是不同的,Pulse只向已经在等待队列中的线程发送信号。这意味着,如果在一个线程中调用Pulse,然后在同一对象上的另一个线程中调用Wait,那么第二个线程将永远等待(死锁)。如果使用等待和脉冲,你必须非常小心,只有在你知道自己在做什么时才使用它,否则你可能只是幸运而已 要使用Monitor、weather AutoReset或ManualReset自己创建WaitHandle的行为,您需要做的不仅仅是简单的等待/脉冲构造只需使用完成工作所需的工具即可:
如果不能使用简单的锁定或原子操作同步线程,请考虑使用WaitHandles。如果无法将线程与WaitHandles同步,请考虑使用Wait和Pulse。如果遵循以下简单规则,Wait和Pulse也可以:
只需编写一个测试应用程序来测试它们的性能。一个监视器(相当于C#lock语句)维护一个内部队列,保证线程按照它们被阻塞的相同顺序被释放。自动/手动重置事件更简单,并且没有这种开销。自动重置事件不在进程之间共享(互斥锁是共享的)。但它们是本机Windows对象,如果使用过多,您可能会遇到麻烦。从外观上看,AutoReset也可以共享。至少没有什么可以阻止您使用名称创建自动事件,但是AutoResetEvent和ManualResetEvent不允许您传递“名称”。只需使用基类EventWaitHandle即可。AutoResetEvent和ManualResetEvent只是构造函数包装器,它们所做的唯一一件事就是使用EventResetMode.AutoReset或EventResetMode.ManualReset从EventWaitHandle调用构造函数……我不同意您对使用Wait/Pulse的担忧。不冒死锁的风险。Wait/Pulse是线程间信令的核心构建块,它们的性能可能优于*ResetEvent,因为正如Gonzalo正确指出的那样,后者可用于进程间信令,导致开销。@Eugene:Wait/
Pulse
的不正确使用很容易导致死锁。即使是Monitor.Pulse
方法也有竞争条件。如果示例中的第二个线程在第一个线程之前启动,它将死锁。@Groo在C#和Java、C等语言中,多线程编程肯定比单线程编程困难得多。看多线程编程,我不认为等待和脉冲是特别困难的,与之相比,例如无锁/无等待算法的艺术。也就是说,我在第一次使用Wait/Pulse时就引入了一个bug,这就是为什么我建议首先熟悉这个主题,例如通过我提供的链接阅读。@EugeneBeresovksy您的陈述完全正确,这就是为什么我建议只有知道自己在做什么时才使用Wait和Pulse。如果你不知道或只是相信你知道等待/脉冲是如何工作的,你可能只是幸运,随时都有可能陷入麻烦。。。我自己多年来一直使用等待/脉冲以及使用CAS操作的无锁算法,但仍然发现自己在思考此类构造时遇到了麻烦。只是想补充一点,EugeneBeresovksy在其第一条评论中提供的链接是进入.NET线程的最佳起点之一。