《C# 3.0 in a Nutshell》中有关线程的文本解释
-
22-09-2019 - |
题
在读的时候 C# 3.0 简而言之 经过 约瑟夫和本阿尔巴哈里, ,我遇到了以下段落(第 673 页,标题为“使用等待和脉冲发送信号")
“这 监视器 类通过两个静态方法提供另一个信号构造, 等待 和 脉冲. 。原则是您自己使用自定义标志和字段(包含在 锁 语句),然后引入 等待 和 脉冲 用于减轻 CPU 旋转的命令。这种低级方法的优点是只需 等待, 脉冲, ,以及 锁 语句,可以实现的功能 自动重置事件, 手动重置事件, , 和 信号, , 也 等待句柄的静态方法 等待所有 和 等待. 。此外, 等待 和 脉冲在所有等待手柄均受到挑战的情况下,可以适合。”
我的问题是,正确的解释是什么 最后的 句子?
- 具有大量等待句柄的情况,其中仅偶尔对任何特定等待句柄调用 WaitOne()。
- 一种具有大量等待句柄的情况,其中很少有多个线程倾向于在任何特定等待句柄上阻塞。
- 其他一些解释。
还希望了解此类情况的启发性示例,以及如何和/或为什么通过等待和脉冲而不是其他方法更有效地处理它们。
谢谢你!
编辑:我在网上找到了这段文字 这里
解决方案
这意味着在某些情况下,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);
}
等待/脉冲的缺点是更容易出错并犯错误(例如,更新变量并忘记脉冲)。在具有等待句柄的程序与具有等待/脉冲的程序同样简单的情况下,出于这个原因,我建议使用等待句柄。
就效率/资源消耗而言(我认为您提到了这一点),等待/脉冲通常更快、更轻(因为它具有托管实现)。不过,这在实践中很少有什么大不了的。在这一点上,Framework 4.0 包括 ManualResetEvent 和 Semaphore 的低开销托管版本(ManualResetEventSlim 和 SemaphoreSlim)。
Framework 4.0 还提供了更多同步选项,减少了对 Wait/Pulse 的需求:
- 倒计时活动
- 障碍
- PLINQ / 数据并行性(AsParallel、Parallel.Invoke、Parallel.For、Parallel.ForEach)
- 任务和延续
所有这些都比 Wait/Pulse 级别高得多,并且 IMO 更适合编写可靠且可维护的代码(假设它们将解决手头的任务)。