7

在阅读Joseph 和 Ben Albahari的 C# 3.0 in a Nutshell时,我遇到了以下段落(第 673 页,标题为“使用等待和脉冲发出信号”的部分中的第一段)

Monitor类通过两个静态方法WaitPulse提供了另一种信号构造。原理是您自己使用自定义标志和字段(包含在lock语句中)编写信号逻辑,然后引入WaitPulse命令来缓解 CPU 旋转. 这种低级方法的优点是只需要WaitPulselock语句,就可以实现AutoResetEventManualResetEventSemaphore以及WaitHandle的功能的静态方法WaitAllWaitAny。此外,WaitPulse 在所有等待句柄都受到严格挑战的情况下也可以使用。”

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

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

还希望能提供此类情况的说明性示例,以及如何和/或为什么通过等待和脉冲而不是其他方法更有效地处理它们。

谢谢!

编辑:我在这里找到了网上的文字

4

1 回答 1

5

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

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

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

lock (_locker)
{
  while (_x < 10 && _y < 20) Monitor.Wait (_locker);
}

然后另一个线程可以自动更新 _x 和 _y(通过锁),然后 Pulse 向服务员发出信号:

lock (_locker)
{
  _x = 20;
  _y = 30;
  Monitor.Pulse (_locker);
} 

Wait/Pulse 的缺点是更容易出错和出错(例如,通过更新变量并忘记 Pulse)。在具有等待句柄的程序与具有等待/脉冲的程序同样简单的情况下,出于这个原因,我建议使用等待句柄。

就效率/资源消耗(我认为您是在暗示)而言,Wait/Pulse 通常更快更轻(因为它具有托管实现)。不过,这在实践中很少有什么大不了的。在这一点上,Framework 4.0 包括 ManualResetEvent 和 Semaphore(ManualResetEventSlim 和 SemaphoreSlim)的低开销托管版本。

Framework 4.0 还提供了更多同步选项,以减少对等待/脉冲的需求:

  • 倒计时事件
  • 障碍
  • PLINQ / 数据并行(AsParallel、Parallel.Invoke、Parallel.For、Parallel.ForEach)
  • 任务和延续

所有这些都比等待/脉冲要高得多,而且 IMO 更适合编写可靠和可维护的代码(假设它们将解决手头的任务)。

于 2010-02-24T01:31:59.690 回答