我仍然不确定这两个调用之间的区别。根据MSDN文档,
Monitor.Enter(Object)
会在指定对象上获取独占锁。
Monitor.Wait(Object)
会释放一个对象上的锁并阻塞当前线程,直到重新获取锁。
由此我认为Monitor.Wait与Monitor.Enter相同,只是在重新获取锁之前先释放了对象上的锁。
当前线程是否必须首先拥有锁?不同的线程如何强制释放对象的锁?为什么同一线程需要重新获取锁?
我仍然不确定这两个调用之间的区别。根据MSDN文档,
Monitor.Enter(Object)
会在指定对象上获取独占锁。
Monitor.Wait(Object)
会释放一个对象上的锁并阻塞当前线程,直到重新获取锁。
由此我认为Monitor.Wait与Monitor.Enter相同,只是在重新获取锁之前先释放了对象上的锁。
当前线程是否必须首先拥有锁?不同的线程如何强制释放对象的锁?为什么同一线程需要重新获取锁?
Monitor.Wait(Object)
,而你需要调用Monitor.Enter(Object)
来获取锁。换句话说,如果调用线程没有指定对象的锁,则会出现SynchronizationLockException异常。至于为什么需要Monitor.Wait
:如果线程意识到它缺少继续执行所需的信息(例如,它正在等待信号),则可能希望让其他线程进入关键部分,因为并非所有线程都具有相同的前提条件。要使等待线程继续执行,您需要在释放锁之前调用Monitor.Pulse(Object)
或Monitor.PulseAll(Object)
(否则,您将获得与Monitor.Wait(Object)
相同类型的异常)。// make sure to synchronize this correctly ;)
while (ConditionNotMet)
{
Monitor.Wait(mutex);
if (ConditionNotMet) // We woke up, but our condition is still not met
Monitor.Pulse(mutex); // Perhaps another waiting thread wants to wake up?
}
public class EnterExitExample
{
private object myLock;
private bool running;
private void ThreadProc1()
{
while (running)
{
lock (myLock)
{
// Do stuff here...
}
Thread.Yield();
}
}
private void ThreadProc2()
{
while (running)
{
lock (myLock)
{
// Do other stuff here...
}
Thread.Yield();
}
}
}
lock (myLock)
语法只是Monitor.Enter(myLock)
和Monitor.Exit(myLock)
的简化形式。Wait
和Pulse
。public class PulseWaitExample
{
private Queue<object> queue;
private bool running;
private void ProducerThreadProc()
{
while (running)
{
object produced = ...; // Do production stuff here.
lock (queue)
{
queue.Enqueue(produced);
Monitor.Pulse(queue);
}
}
}
private void ConsumerThreadProc()
{
while (running)
{
object toBeConsumed;
lock (queue)
{
Monitor.Wait(queue);
toBeConsumed = queue.Dequeue();
}
// Do consuming stuff with toBeConsumed here.
}
}
}
这是什么?
生产者在任何时候都可以生产对象。一旦他生产出一个对象,就会获得队列的锁,并将该对象入队,然后进行 Pulse
调用。
与此同时,消费者没有锁定,他通过调用 Wait
来释放锁。一旦他在该对象上收到 Pulse
,他将重新锁定并执行消费操作。
因此,您在这里拥有直接的线程通知,告诉消费者有事情要做。如果没有这个,您只能让消费者不断轮询集合以查看是否还有任务需要处理。使用 Wait
,您可以确保有任务需要处理。
Queue.Enqueue
和Monitor.Pulse
的调用,后者会释放锁。消费者要么完全不在锁块之内,这意味着他只需获取锁,调用Wait
,由于持续的Pulse
而立即停止等待;或者他正在Wait
调用中,这使得他重新获取锁并执行消费操作。 - Jan Dörrenhauspublic class PulseWaitExample
{
private Queue<object> queue;
private bool running;
private void ProducerThreadProc()
{
while (running)
{
object produced = ...; // Do production stuff here.
lock (queue)
{
queue.Enqueue(produced);
Monitor.Pulse(queue);
}
}
}
private void ConsumerThreadProc()
{
while (running)
{
object toBeConsumed;
lock (queue)
{
// here is the fix
if (queue.Count == 0)
{
Monitor.Wait(queue);
}
toBeConsumed = queue.Dequeue();
}
// Do consuming stuff with toBeConsumed here.
}
}
}