我仍然不确定这两个调用之间的区别。来自MSDN,
Monitor.Enter(Object)获取指定对象上的排它锁。
Monitor.Wait(Object)释放对象上的锁,并阻塞当前线程,直到它重新获得锁。
由此,我假设Monitor.Wait与Monitor.Enter相同,只是它首先释放对象上的锁,然后再重新获取。
当前线程必须首先拥有锁吗?一个不同的线程怎么能强制释放一个对象的锁?为什么同一线程要重新获取锁?
发布于 2013-06-05 22:41:47
根据MSDN: Monitor.Wait Method(Object)的说法
SynchronizationLockException:调用线程不拥有指定对象的锁。
换句话说:当你已经拥有锁时,你只能调用Monitor.Wait(Object),而你调用Monitor.Enter(Object)是为了获得锁。
至于为什么需要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?
}发布于 2013-06-05 22:46:32
考虑这个例子:
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();
}
}
}现在您有两个线程,每个线程都在等待锁,然后做自己的事情,然后释放锁。对于Monitor.Enter(myLock)和Monitor.Exit(myLock)来说,lock (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,您可以确保存在。
发布于 2018-06-12 17:11:50
正如Cristi提到的,天真的等待/脉冲代码不起作用。因为您完全忽略了这里的关键点:监视器不是一个消息队列。如果你的脉搏没有人在等待,那么脉搏就消失了。正确的哲学是,你在等待一个条件,如果条件不满足,有一种方法可以等待它,而不需要占用cpu和锁。在这里,消费者的条件是队列中有东西。参见https://ideone.com/tWqTS1 which (来自Cristi的示例的分支)。
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)
{
// here is the fix
if (queue.Count == 0)
{
Monitor.Wait(queue);
}
toBeConsumed = queue.Dequeue();
}
// Do consuming stuff with toBeConsumed here.
}
}
}https://stackoverflow.com/questions/16942538
复制相似问题