Monitor.Wait - пока или если? - PullRequest
5 голосов
/ 16 января 2012

В настоящее время я готовлюсь к экзамену по многопоточности.Я прочитал хорошую статью о потоках работ Альбахари .У меня вопрос по использованию монитора - почему здесь используется цикл вместо if?

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

Я думаю, что if будет достаточно.

I 'боюсь, что я не совсем понимаю статью.

// Редактировать пример кода:

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!!!");
  }
}

Ответы [ 5 ]

5 голосов
/ 16 января 2012

Это зависит только от ситуации. В этом случае код просто ждет, пока _go станет true .

Каждый раз, когда _locker пульсирует, он проверит, установлено ли _go на true . Если _go по-прежнему false , он будет ожидать следующего импульса.

Если , если используется вместо , тогда как , он будет ждать только один раз (или не будет вовсе, если _go уже true ), и затем продолжится после импульса, независимо от нового состояния _go.

То, как вы используете Monitor.Wait (), полностью зависит от ваших конкретных потребностей.

3 голосов
/ 16 января 2012

Это действительно зависит только от ситуации.Но сначала нам нужно уточнить, как работают мониторы.Когда поток продолжает сигнализировать поток через Monitor.Pulse (), обычно нет никакой гарантии, что сигнальный поток действительно будет работать следующим.Это означает, что другие потоки могут запускаться до сигнального потока и изменять условие, при котором для сигнального потока было нормально работать.Это означает, что сигнализируемый поток все еще должен проверить, безопасно ли продолжать его после пробуждения (то есть цикла while).Однако некоторые редкие проблемы с синхронизацией позволяют предположить, что после того, как потоку было сообщено о пробуждении (т. Е. Monitor.Pulse ()), ни один другой поток не может изменить условие, при котором можно безопасно продолжать (т.е.условие if).

2 голосов
/ 16 января 2012

Я написал статью, которая может помочь здесь: Ожидание и демистификация импульса

Там происходит больше, чем сразу видно.

1 голос
/ 19 марта 2012

У меня возник вопрос при использовании монитора - почему здесь используется цикл вместо if?

При работе с Pulse существует хорошо известное правило.и Wait, в котором говорится, что в случае сомнения предпочитайте while вместо if.Ясно, что любой из них будет работать в этом случае, но почти во всех остальных ситуациях требуется while.На самом деле, существует очень немного (если есть) сценариев, в которых использование цикла while может привести к неверному результату.Это основа для этого общего правила.Автор использовал цикл while, потому что он пытался придерживаться проверенного паттерна.Он даже предоставляет шаблон в той же статье.Вот оно:

lock (_locker)
  while ( <blocking-condition> )
    Monitor.Wait (_locker);
0 голосов
/ 28 февраля 2014

Самый простой способ написать правильный код с помощью Monitor.Wait - это предположить, что система будет расценивать его как «рекомендательный», и предположить, что система может произвольно разбудить любой ожидающий поток в любой момент, когда она может получить блокировку, независимо от того,Pulse был вызван.Система, как правило, не будет делать это, конечно, но если программа использует Wait и Pulse должным образом, на ее правильность не должно влиять то, что вызовы Wait произвольно завершаются рано, нетпричина.По сути, следует рассматривать Wait как средство сообщения системе: «Продолжение выполнения в прошлом здесь будет пустой тратой времени, пока кто-нибудь еще не вызовет Pulse».

...