首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Monitor.Enter vs Monitor.Wait

Monitor.Enter vs Monitor.Wait
EN

Stack Overflow用户
提问于 2013-06-05 22:25:38
回答 3查看 6.3K关注 0票数 6

我仍然不确定这两个调用之间的区别。来自MSDN,

Monitor.Enter(Object)获取指定对象上的排它锁。

Monitor.Wait(Object)释放对象上的锁,并阻塞当前线程,直到它重新获得锁。

由此,我假设Monitor.Wait与Monitor.Enter相同,只是它首先释放对象上的锁,然后再重新获取。

当前线程必须首先拥有锁吗?一个不同的线程怎么能强制释放一个对象的锁?为什么同一线程要重新获取锁?

EN

回答 3

Stack Overflow用户

发布于 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)相同的异常)。

请记住,在一个脉冲之后和在锁被释放之后,获取锁的下一个线程不一定是接收到该脉冲的线程。

还要记住,收到一个脉冲,并不等同于你的条件得到满足。你可能还需要再等一段时间:

代码语言:javascript
复制
// 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?
}
票数 8
EN

Stack Overflow用户

发布于 2013-06-05 22:46:32

考虑这个例子:

代码语言:javascript
复制
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)语法只是一种糖分。

现在让我们看一个更复杂的例子,在这个例子中,WaitPulse发挥了作用。

代码语言:javascript
复制
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,您可以确保存在。

票数 1
EN

Stack Overflow用户

发布于 2018-06-12 17:11:50

正如Cristi提到的,天真的等待/脉冲代码不起作用。因为您完全忽略了这里的关键点:监视器不是一个消息队列。如果你的脉搏没有人在等待,那么脉搏就消失了。正确的哲学是,你在等待一个条件,如果条件不满足,有一种方法可以等待它,而不需要占用cpu和锁。在这里,消费者的条件是队列中有东西。参见https://ideone.com/tWqTS1 which (来自Cristi的示例的分支)。

代码语言:javascript
复制
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.
        }
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16942538

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档