[英]C# Producer-Consumer pattern with Monitor.Wait and Monitor.Pulse
考虑以下阻止生产者线程和使用者线程的实现:
static void Main(string[] args)
{
var syncRoot = new object();
var products = new List<int>();
Action producer = () => {
lock (syncRoot)
{
var counter = 0;
while (true)
{
products.Add(counter++);
Monitor.Pulse(syncRoot);
Monitor.Wait(syncRoot);
}
}};
Action consumer = () => {
lock (syncRoot)
while (true)
{
Monitor.Pulse(syncRoot);
products.ForEach(Console.WriteLine);
products.Clear();
Thread.Sleep(500);
Monitor.Wait(syncRoot);
}};
Task.Factory.StartNew(producer);
Task.Factory.StartNew(consumer);
Console.ReadLine();
}
假设当生产线程进入Monitor.Wait
它等待两件事:
在上面的代码中,我在Pulse
和Wait
调用之间进行了繁琐的工作。
因此,如果我这样编写我的使用线程(在等待之前立即脉冲):
Action consumer = () =>
{
lock (syncRoot)
while (true)
{
products.ForEach(Console.WriteLine);
products.Clear();
Thread.Sleep(500);
Monitor.Pulse(syncRoot);
Monitor.Wait(syncRoot);
}
};
我没有发现任何行为上的变化。 有什么指导方针吗? 我们通常应该在Wait
之前立即Pulse
还是在性能方面有所不同?
“先脉冲再等待”与“先脉冲再等待”几乎相同,因为它们在无限循环中运行。 脉冲,等待,脉冲,等待与等待,脉冲,等待,脉冲几乎相同
通常,等待更改的线程使用Wait
,而执行更改的线程使用Pulse
。 线程可以同时执行这两种操作,但是一般情况取决于情况。
给定的代码在按住锁的同时正在休眠。 出于学习/模拟的目的,这很好,但是生产代码通常不应该这样做。 您可以将超时传递给Wait
,这很好,并且在等待期间不持有锁。
一般来说,Monitor被视为低级同步原语,建议改用高级同步原语。 理解Monitor等低级原语是一件好事,但是通常的智慧是,对于几乎任何实际情况,都可以使用一些高级原语,这些原语不太容易出错,不太可能隐藏某些棘手的比赛情况,并且更容易在某人中阅读。其他的代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.