Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 自动复位事件、手动复位事件与监视器_.net_Concurrency_Synchronization_.net 3.5 - Fatal编程技术网

.net 自动复位事件、手动复位事件与监视器

.net 自动复位事件、手动复位事件与监视器,.net,concurrency,synchronization,.net-3.5,.net,Concurrency,Synchronization,.net 3.5,假设我必须在.NET3.5SP1中协调一个同步算法,标题中列出的任何同步原语都非常适合该任务 从性能的角度来看,其中有哪一个比其他的性能更好 我问这个问题是因为我已经编写了一段时间了,但对这个主题没有适当的了解。如果可以,请使用Monitor。它类似于一个关键部分。AutoResetEvent/ManualResetEvent的开销可能稍大一些,因为它们可以由不同的进程共享,而监视器属于单个进程。WaitHandles看起来与Wait/Pulse构造非常相似,但区别在于细节:WaitHandle

假设我必须在.NET3.5SP1中协调一个同步算法,标题中列出的任何同步原语都非常适合该任务

从性能的角度来看,其中有哪一个比其他的性能更好


我问这个问题是因为我已经编写了一段时间了,但对这个主题没有适当的了解。

如果可以,请使用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线程的最佳起点之一。