根据MSDN,Monitor.Wait()
:
释放对象的锁定并阻止当前线程直到它 重新获得锁定。
然而,我所读到的关于Wait()和Pulse()的所有内容似乎表明仅仅释放另一个线程上的锁是不够的。我需要先调用Pulse()来唤醒等待的线程。
我的问题是为什么?在Monitor.Enter()上等待锁的线程只是在它被释放时获取它。没有必要“唤醒他们”。它似乎打败了Wait()的有用性。
例如
static object _lock = new Object();
static void Main()
{
new Thread(Count).Start();
Sleep(10);
lock (_lock)
{
Console.WriteLine("Main thread grabbed lock");
Monitor.Pulse(_lock) //Why is this required when we're about to release the lock anyway?
}
}
static void Count()
{
lock (_lock)
{
int count = 0;
while(true)
{
Writeline("Count: " + count++);
//give other threads a chance every 10th iteration
if (count % 10 == 0)
Monitor.Wait(_lock);
}
}
}
如果我使用Exit()和Enter()而不是Wait(),我可以这样做:
static object _lock = new Object();
static void Main()
{
new Thread(Count).Start();
Sleep(10);
lock (_lock) Console.WriteLine("Main thread grabbed lock");
}
static void Count()
{
lock (_lock)
{
int count = 0;
while(true)
{
Writeline("Count: " + count++);
//give other threads a chance every 10th iteration
if (count % 10 == 0)
{
Monitor.Exit(_lock);
Monitor.Enter(_lock);
}
}
}
}
答案 0 :(得分:35)
您使用Enter
/ Exit
获取对锁的独占访问权。
您使用Wait
/ Pulse
来允许合作通知:我想等待某事发生,所以我进入锁定并致电Wait
;通知代码将进入锁定并致电Pulse
。
这两个方案是相关的,但他们并没有试图完成同样的事情。
考虑一下如何实现一个生产者/消费者队列,消费者可以在没有这样的东西的情况下说“当我有一件物品供我消费时叫醒我”。
答案 1 :(得分:9)
阅读链接的MSDN页面的备注部分:
当线程调用Wait时,它会释放对象的锁定并进入对象的等待队列。对象的就绪队列中的下一个线程(如果有)获取锁并且独占使用该对象。 所有调用Wait的线程都会保留在等待队列中,直到它们收到来自Pulse所有者发送的Pulse或PulseAll 的信号。如果发送Pulse,则只有等待队列头部的线程受到影响。如果发送PulseAll,则等待该对象的所有线程都会受到影响。当接收到信号时,一个或多个线程离开等待队列并进入就绪队列。允许就绪队列中的线程重新获取锁定。
当调用线程重新获取对象上的锁时,此方法返回。 请注意,如果锁的持有者未调用Pulse或PulseAll ,此方法将无限期阻止。
所以,基本上,当你调用Monitor.Wait
时,你的线程就在等待队列中。要重新获取锁,它需要处于就绪队列中。 Monitor.Pulse
将等待队列中的第一个线程移动到就绪队列,从而允许它重新获取锁。
答案 2 :(得分:8)
我自己也有同样的怀疑,尽管有一些有趣的答案(其中一些存在于此),我仍然一直在寻找更有说服力的答案。
我认为关于这个问题的一个有趣且简单的想法是:我可以在特定时刻调用 Monitor.Wait(lockObj),其中没有其他线程等待获取< strong> lockObj 对象。我只是想等待一些事情发生(例如,某些对象的状态要改变),这是我知道最终会在其他线程上发生的事情。一旦达到这个条件,我希望能够在另一个线程释放锁定后立即重新获取锁。
通过 Monitor.Wait 方法的定义,它会释放锁并尝试再次获取它。如果它在尝试再次获取锁之前没有等待 Monitor.Pulse 方法被调用,它只会释放锁并立即再次获取它(取决于您的代码,可能在循环中。
也就是说,我认为通过查看 Monitor.Wait 强>方法。
这样想:&#34;我不想释放这个锁并立即尝试再次获取它,因为我不想成为下一个获取此锁的线程。而且我也不想留在一个循环中,其中包含对 Thread.Sleep 的调用,检查一些标志或某些东西,以便知道我等待的条件何时达到这样我就可以尝试重新获取锁定。我只是想'休眠'#39;一旦有人告诉我我等待的条件已经实现,就会自动唤醒。&#34;。