Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Don';I don’我不明白监视的必要性_C#_Multithreading_Synchronization - Fatal编程技术网

C# Don';I don’我不明白监视的必要性

C# Don';I don’我不明白监视的必要性,c#,multithreading,synchronization,C#,Multithreading,Synchronization,根据,Monitor.Wait(): 释放对象上的锁并阻止当前线程,直到 重新获得锁 然而,我读到的关于Wait()和Pulse()的所有内容似乎都表明,仅仅释放另一个线程上的锁是不够的。我需要先调用Pulse()来唤醒等待的线程 我的问题是为什么?线程等待监视器上的锁。Enter()在释放锁时获取它。没有必要“唤醒他们”。它似乎破坏了Wait()的作用 例如 如果使用Exit()和Enter()而不是Wait(),则可以执行以下操作: static object _lock = new Obj

根据,
Monitor.Wait()

释放对象上的锁并阻止当前线程,直到 重新获得锁

然而,我读到的关于Wait()和Pulse()的所有内容似乎都表明,仅仅释放另一个线程上的锁是不够的。我需要先调用Pulse()来唤醒等待的线程

我的问题是为什么?线程等待监视器上的锁。Enter()在释放锁时获取它。没有必要“唤醒他们”。它似乎破坏了Wait()的作用

例如

如果使用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);
            }
        }
    }
}

阅读链接MSDN页面的备注部分:

当线程调用Wait时,它释放对象上的锁并进入对象的等待队列。对象的就绪队列中的下一个线程(如果有)获取锁并独占使用该对象所有调用Wait的线程都将保持在等待队列中,直到它们收到锁所有者发送的来自Pulse或PULSELL的信号。如果发送脉冲,则仅影响等待队列头部的线程。如果发送PULSELL,则等待对象的所有线程都会受到影响。当接收到信号时,一个或多个线程离开等待队列并进入就绪队列。允许就绪队列中的线程重新获取锁

当调用线程重新获取对象上的锁时,此方法返回请注意,如果锁的保持器不调用Pulse或PULSELL,则此方法将无限期阻止


因此,基本上,当您调用
Monitor.Wait
时,您的线程处于等待队列中。为了重新获取锁,它需要处于就绪队列中
Monitor.Pulse
将等待队列中的第一个线程移动到就绪队列,从而允许它重新获取锁。

您可以使用
输入
/
退出
获取对锁的独占访问权

您使用
Wait
/
Pulse
来允许合作通知:我想等待某些事情发生,所以我进入锁并调用
Wait
;通知代码将进入锁并调用
脉冲

这两个计划是相关的,但它们并没有试图完成相同的事情


考虑一下如何实现一个生产者/消费者队列,在这个队列中,消费者可以说“当你有一个商品要我消费时叫醒我”,而不需要这样做。

我自己也有同样的疑问,尽管有一些有趣的答案(其中一些在这里),我仍然在寻找一个更令人信服的答案

我认为关于这个问题的一个有趣而简单的想法是:我可以在没有其他线程等待获取lockObj对象锁的特定时刻调用Monitor.Wait(lockObj)。我只想等待一些事情发生(例如,某个对象的状态发生变化),我知道这是最终会在其他线程上发生的事情。一旦达到这个条件,我希望能够在另一个线程释放其锁时重新获取锁

根据Monitor.Wait方法的定义,它释放锁并再次尝试获取它。如果它在再次尝试获取锁之前没有等待调用Monitor.Pulse方法,它只需释放锁并立即再次获取它(取决于代码,可能在循环中)

也就是说,我认为通过观察Monitor.Wait方法在功能上的作用来理解Monitor.Pulse方法的需求是很有趣的


这样想:“我不想释放此锁并立即尝试再次获取它,因为我不想成为下一个获取此锁的线程。我也不想停留在一个循环中,循环中包含对线程的调用。Sleep检查一些标志或其他东西,以便知道我等待的条件何时达到,以便我可以尝试重新获取锁。我只想“冬眠”,一旦有人告诉我等待的条件已经达到,我就会自动被唤醒。”。

是的,但是为什么要将“等待”和“准备”分开呢“排队?它有什么好处可以弥补我必须拨打额外电话的缺点?+1表示等待队列:另请参阅以获得简单的图形说明。@GazTheDestroyer如果不使用等待队列,则必须进行主动轮询。在许多情况下,这是不可取的,也是无效的。请看生产商和消费者以不同的速度工作。我想我会使用AutoResetEvent。等待/脉冲给了我额外的东西吗?@GazTheDestroyer:IMO,
AutoResetEvent
使用起来更安全。如果不小心执行Wait/Pulse同步,等待线程可能会很容易错过脉冲并永远继续等待。@GazTheDestroyer:就个人而言,我更喜欢Wait/Pulse,我相信在某些情况下它们更有效。与Groo相反,我发现编写没有Wait/Pulse竞争条件的代码更容易,这正是因为Wait和Pulse都必须在已经拥有监视器的线程的上下文中调用。我想这是一个偏好问题。我在几个例子中发现了Wait/Pulse代码中的竞争条件。即使是也有死锁,这表明这个构造是多么微妙。很好地总结了我的观点。@Gazedthedestroyer:你问等待/脉冲给了你什么,而AutoResetEvent没有。它使您能够编写AutoResetEvent,这就是它所做的。像自动重置事件这样的复杂门必须由某些东西构建,如果框架没有恰好提供您个人需要的复杂门的味道,那么如果没有等待和脉冲,您将用哪些部分构建它?
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);
            }
        }
    }
}