【问题标题】:Monitor.Wait - while or if?Monitor.Wait - 同时还是如果?
【发布时间】:2012-02-11 16:36:03
【问题描述】:

目前,我正在学习多线程考试。我读了the good threading article of albahari。我对监视器的使用有疑问 - 为什么这里使用循环代替 if?

lock (_locker)
{
  while (!_go) //why while and not if?
    Monitor.Wait (_locker);  // _lock is released
  // lock is regained
  ...
}

我认为,一个 if 就足够了。

恐怕我没有完全理解这篇文章。

//编辑 示例代码:

class SimpleWaitPulse
{
  static readonly object _locker = new object();
  static bool _go;

  static void Main()
  {                                // The new thread will block
    new Thread (Work).Start();     // because _go==false.

    Console.ReadLine();            // Wait for user to hit Enter

    lock (_locker)                 // Let's now wake up the thread by
    {                              // setting _go=true and pulsing.
      _go = true;
      Monitor.Pulse (_locker);
    }
  }

  static void Work()
  {
    lock (_locker)
      while (!_go)
        Monitor.Wait (_locker);    // Lock is released while we’re waiting

    Console.WriteLine ("Woken!!!");
  }
}

【问题讨论】:

  • "If" 只检查一次。 “while”循环将继续检查。如果不等。等待中。
  • 嗨,DOK - 感谢您的解释。但我认为,Monitor.Wait 操作只会执行一次。它将等待脉冲信号。所以我暂时看不到任何理由:-(
  • 这取决于程序的其余部分,例如 _go 的确切含义,以及您何时设置它。
  • 嗨 svick - 感谢您的回答。我已经添加了示例。
  • 亲,这真的取决于你想等待事件发生多少次。通常,锁定后内存中有某种类型的修改,如果您只想“观察”一次修改,那么您可以使用 if(例如,您发送消息并等待单个响应)。如果您想持续“观察”修改,请在 while 循环中执行(即,您正在监视消息流中是否有大量消息)。

标签: c# multithreading monitor


【解决方案1】:

这取决于情况。在这种情况下,代码只是在等待 _go 变为 true

每次_locker 发出脉冲时,它都会检查_go 是否已设置为true。如果_go 仍然是false,它将等待下一个脉冲。

如果使用 if 而不是 while,它只会等待一次(如果 _go 已经 true 则根本不会等待>),然后会在一个脉冲后继续,无论_go 的新状态如何。

因此,如何使用 Monitor.Wait() 完全取决于您的特定需求。

【讨论】:

    【解决方案2】:

    这真的取决于情况。但首先,我们需要澄清 Monitors 是如何工作的。当线程继续通过 Monitor.Pulse() 向线程发出信号时,通常不能保证发出信号的线程接下来会实际运行。这意味着其他线程有可能在发出信号的线程之前运行并更改发出信号的线程可以继续进行的条件。这意味着发出信号的线程在被唤醒(即while循环)后仍然需要检查它是否安全以继续进行。但是,某些罕见的同步问题允许您假设一旦一个线程被通知唤醒(即 Monitor.Pulse()),没有其他线程能够更改它可以安全继续的条件(即.if 条件)。

    【讨论】:

      【解决方案3】:

      我写了一篇文章可能对这里有帮助:Wait and Pulse demystified

      发生的事情比显而易见的要多。

      【讨论】:

        【解决方案4】:

        我有一个关于监视器使用的问题 - 为什么这里使用循环 if 的地方?

        在使用PulseWait 时有一条众所周知的规则,即当有疑问时,首选while 而不是if。显然,在这种情况下,任何一个都可以工作,但在几乎所有其他情况下,while 都是必需的。事实上,使用while 循环会产生错误结果的情况很少(如果有的话)。这是这个一般规则的基础。作者使用了while 循环,因为他试图坚持久经考验的模式。他甚至在同一篇文章中提供了模板。就是这样:

        lock (_locker)
          while ( <blocking-condition> )
            Monitor.Wait (_locker);
        

        【讨论】:

          【解决方案5】:

          Monitor.Wait编写正确代码的最简单方法是假设系统将其视为“建议”,并假设系统可以在任何时候任意唤醒任何等待的线程它可以获取锁,而不考虑是否Pulse 已被调用。当然,系统通常不会这样做,但是如果程序正确使用了WaitPulse,它的正确性不应该受到Wait 调用任意提前退出的影响没有理由。从本质上讲,人们应该将Wait 视为一种告诉系统“在此处继续执行将是浪费时间,除非或直到其他人调用Pulse”。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-08-11
            • 1970-01-01
            • 1970-01-01
            • 2011-09-13
            • 2011-05-23
            相关资源
            最近更新 更多