"C#3.0 in a Nutshell"中的线程文本说明

RAL*_*RAL 7 multithreading wait pulse waithandle

在阅读果壳中的C#3.0约瑟夫和Ben阿尔巴哈利,我碰到下面的段落来了(673页,在标题的部分第一段" 与等待信令和脉冲 ")

" Monitor类通过两种静态方法WaitPulse提供另一种信令构造.原理是您使用自定义标志和字段(包含在锁定语句中)自己编写信令逻辑,然后引入WaitPulse命令来缓解CPU旋转这种低层次的方法的优点是,只有等待,脉搏锁定语句,可以实现的功能的AutoResetEvent,ManualResetEvent的,和信号量,以及WaitHandle中的静态方法为WaitAll了WaitAny.此外,等待脉冲 可以在所有的等待句柄都吝啬挑战的情况下适用的."

我的问题是,对最后一句的正确解释是什么?

  • 具有适当/大量等待句柄的情况,其中WaitOne()仅偶尔在任何特定等待句柄上调用.
  • 具有相当/大量等待句柄的情况,其中很少有多个线程倾向于阻塞任何特定的等待句柄.
  • 其他一些解释.

还将欣赏这种情况的有启发性的例子,以及可能通过等待和脉冲而不是通过其他方法更有效地处理它们的方式和/或原因.

谢谢!

编辑:我在这里找到了在线文本

Joe*_*ari 5

这就是说,在某些情况下,Wait和Pulse提供比等待句柄更简单的解决方案.一般来说,这发生在:

  • 服务员而不是通知者决定何时解除阻止
  • 阻塞条件涉及的不仅仅是一个简单的标志(可能是几个变量)

在这些情况下,您仍然可以使用等待句柄,但Wait/Pulse往往更简单.Wait/Pulse的好处是Wait等待时释放底层锁.例如,在下面的示例中,我们在锁的安全性内读取_x和_y - 然后在等待时释放该锁,以便另一个线程可以更新这些变量:

lock (_locker)
{
  while (_x < 10 && _y < 20) Monitor.Wait (_locker);
}
Run Code Online (Sandbox Code Playgroud)

然后另一个线程可以原子地(通过锁定)更新_x和_y,然后使用Pulse来向服务员发出信号:

lock (_locker)
{
  _x = 20;
  _y = 30;
  Monitor.Pulse (_locker);
} 
Run Code Online (Sandbox Code Playgroud)

Wait/Pulse的缺点是更容易弄错并犯错(例如,通过更新变量而忘记Pulse).在具有等待句柄的程序对于具有Wait/Pulse的程序同样简单的情况下,我建议使用等待句柄.

在效率/资源消耗方面(我认为你提到的),Wait/Pulse通常更快更轻(因为它有一个托管实现).不过,这在实践中很少是一件大事.在这一点上,Framework 4.0包括ManualResetEvent和Semaphore(ManualResetEventSlim和SemaphoreSlim)的低开销托管版本.

Framework 4.0还提供了更多的同步选项,减少了对Wait/Pulse的需求:

  • CountdownEvent
  • 屏障
  • PLINQ /数据并行(AsParallel,Parallel.Invoke,Parallel.For,Parallel.ForEach)
  • 任务和延续

所有这些都比Wait/Pulse高得多,IMO更适合编写可靠和可维护的代码(假设他们将解决手头的任务).