Monitor.Pulse&Wait – 意外行为

http://www.codeproject.com/Articles/28785/Thread-synchronization-Wait-and-Pulse-demystified

队列:

就绪队列是等待特定锁的线程集合。 Monitor.Wait方法引入了另一个队列:等待队列。 这是必需的,因为等待Pulse与等待获取锁定不同。 与就绪队列一样,等待队列是FIFO。

推荐图案:

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

* Q =队列。

通过这个,我明白当我打电话给Pulse ,它会在它结束前做两件事。 首先,它将一个线程从等待Q中移除到就绪Q.其次,它允许Ready Q中的一个线程(不知道谁是该线程)获得锁定; 它不关心谁获取锁(来自等待Q的线程或由于某种原因在准备好的Q中的线程)。

如果我是对的,那么为什么Monitor.Wait帮助解决问题之前花一点时间(问题 – 即使来自等待Q的线程没有获得锁定,脉冲结束)?

A. 告诉我,我是否对Monitor.Pulse的目的是正确的。

B。 为什么我需要在Monitor.Wait之前放一段while

以下答案的完整代码:

 class Program { static Queue queue = new Queue(); static object someMonitor = new object(); static void Main(string[] args) { Thread Thread1 = new Thread(WorkAlltheTime); Thread1.Name = "Thread1"; Thread Thread2 = new Thread(WorkAlltheTime); Thread2.Name = "Thread2"; Thread Thread3 = new Thread(WorkOnce); Thread3.Name = "Thread3"; Thread1.Start(); Thread2.Start(); Thread.Sleep(1000); Thread3.Start(); Console.ReadLine(); } static void WorkAlltheTime() { Console.WriteLine("Came in to Ready Q: " + Thread.CurrentThread.Name); lock (someMonitor) { Console.WriteLine("Came out from Ready Q: " + Thread.CurrentThread.Name); // Broken! while (queue.Count == 0) { Console.WriteLine("Came in to Waiting Q: " + Thread.CurrentThread.Name); Monitor.Wait(someMonitor); Console.WriteLine("Came out from Waiting Q: " + Thread.CurrentThread.Name); } queue.Dequeue(); Console.WriteLine("Thread: "+Thread.CurrentThread.Name+" Pulled Out"); } } static void WorkOnce() { lock (someMonitor) { queue.Enqueue(1); Monitor.Pulse(someMonitor); } } } 

想象一下,您正在尝试编写生产者/消费者队列 – 每次生成项目时都会使用Pulse ,而消费者需要等到有消耗的项目。 你会写这样的代码:

 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循环,您将再次等待,直到生成下一个项目,这是您真正想要的。