C# 监护仪.脉搏和脉搏;等待-意外行为

C# 监护仪.脉搏和脉搏;等待-意外行为,c#,locking,monitor,C#,Locking,Monitor,队列: 就绪队列是正在等待队列的线程的集合 特殊的锁。Wait方法引入另一个队列: 排队等候。这是必需的,因为等待脉冲是不同的 从等待获得锁。像就绪队列一样,等待 队列是FIFO 推荐模式: 这些队列可能导致意外行为。当脉冲出现时, 等待队列的头被释放并添加到就绪队列中 队列但是,如果就绪队列中有其他线程,则 将在释放线程之前获取锁。这是一个 问题,因为获取锁的线程可以改变状态 脉冲线程所依赖的。解决办法是使用一段时间 lock语句中的条件 *Q=队列 这样,我知道当我调用Pulse时,它会在结

队列:

就绪队列是正在等待队列的线程的集合 特殊的锁。Wait方法引入另一个队列: 排队等候。这是必需的,因为等待脉冲是不同的 从等待获得锁。像就绪队列一样,等待 队列是FIFO

推荐模式:

这些队列可能导致意外行为。当脉冲出现时, 等待队列的头被释放并添加到就绪队列中 队列但是,如果就绪队列中有其他线程,则 将在释放线程之前获取锁。这是一个 问题,因为获取锁的线程可以改变状态 脉冲线程所依赖的。解决办法是使用一段时间 lock语句中的条件

*Q=队列

这样,我知道当我调用
Pulse
时,它会在结束前做两件事。首先,它将一个线程从等待的Q移除到准备的Q。其次,它让准备的Q中的一个线程(不知道该线程是谁)获得锁;它不关心谁获得了锁(来自等待Q的线程或出于某种原因处于就绪Q中的线程)

如果我说的没错,那么为什么
监视器之前放置
呢。等待
帮助解决问题(问题-即使来自等待的Q的线程没有获得锁,脉冲也会结束)

A告诉我关于
监视器.Pulse的用途是否正确

B为什么我需要在
监视器之前放置
while
。等待

答案的完整代码如下:

类程序
{
静态队列=新队列();
静态对象someMonitor=新对象();
静态void Main(字符串[]参数)
{
线程线程1=新线程(始终工作);
Thread1.Name=“Thread1”;
螺纹2=新螺纹(始终工作);
Thread2.Name=“Thread2”;
螺纹3=新螺纹(修井);
Thread3.Name=“Thread3”;
Thread1.Start();
Thread2.Start();
睡眠(1000);
Thread3.Start();
Console.ReadLine();
}
静态void始终工作()
{
WriteLine(“进入准备就绪Q:+Thread.CurrentThread.Name”);
锁(监视器)
{
WriteLine(“从Ready Q出来:“+Thread.CurrentThread.Name”);
//坏了!
while(queue.Count==0)
{
WriteLine(“进入等待Q:+Thread.CurrentThread.Name”);
Monitor.Wait(someMonitor);
WriteLine(“从等待Q中出来:“+Thread.CurrentThread.Name”);
}
queue.Dequeue();
WriteLine(“Thread:+Thread.CurrentThread.Name+”拉出”);
}
}
静态孔隙修井()
{
锁(监视器)
{
排队。排队(1);
监视器。脉冲(someMonitor);
}
}   
}

假设您正试图编写一个生产者/消费者队列-您每次生产一个商品时都会发出脉冲,消费者需要等待,直到有商品要消费。您可以编写如下代码:

Foo item;
lock(someMonitor)
{
    while (queue.Count == 0)
    {
        Monitor.Wait(someMonitor);
    }
    item = queue.Dequeue();
}
// Use the item
假设您没有while循环,而是编写:

Foo item;
lock(someMonitor)
{
    // Broken!
    if (queue.Count == 0)
    {
        Monitor.Wait(someMonitor);
    }
    item = queue.Dequeue();
}
// Use the item
现在假设有一个线程已经在等待,然后在lock语句之前有另一个线程。。。然后,制作人向监视器发送脉冲(当然,还会向队列中添加一个项目)

在这一点上,还没有到达锁的线程将是第一个获得锁的线程是完全可行的。。。当“等待”线程获取锁时,队列将再次为空。如果只使用一条
if
语句,没有循环,那么当队列为空时,您将最终退出队列,这将失败


使用while循环,您将再次等待,直到生成下一个项目,这是您真正想要的。

谢谢,我编写了您示例的完整代码,根据您的解释,我对其进行了90次测试,现在我完全理解了。再次谢谢你!