Вы должны понимать, что делают Pulse
, PulseAll
и Wait
.Monitor
поддерживает две очереди: очередь ожидания и очередь готовности.Когда поток вызывает Wait
, он перемещается в очередь ожидания.Когда поток вызывает Pulse
, он перемещает один и только один поток из очереди ожидания в очередь готовности.Когда поток вызывает PulseAll
, он перемещает все потоков из очереди ожидания в очередь готовности.Потоки в очереди готовности могут повторно получить блокировку в любой момент, но, конечно, только после того, как текущий держатель снимает ее.
Исходя из этих знаний, довольно легко понять, почему вы должны перепроверить счетчик очереди, когдаиспользуя PulseAll
.Это связано с тем, что все потоки снятия с очереди в конце концов проснутся и захотят извлечь элемент из очереди.Но что делать, если в очереди только один элемент?Очевидно, что мы должны перепроверить количество очередей, чтобы избежать выгрузки пустой очереди.
Итак, каков был бы вывод, если бы вы использовали Pulse
вместо PulseAll
?Все еще будет проблема с простой проверкой if
.Причина в том, что поток из очереди готовности не обязательно будет следующим потоком для получения блокировки.Это связано с тем, что Monitor
не дает предпочтения вызову Wait
над вызовом Enter
.
Цикл while
является довольно стандартным шаблоном при использовании Monitor.Wait
.Это потому, что пульсация потока не имеет семантического значения сама по себе.Это всего лишь сигнал о том, что состояние блокировки изменилось.Когда потоки просыпаются после блокировки на Wait
, они должны перепроверить то же условие, которое первоначально использовалось для блокировки потока, чтобы увидеть, может ли поток теперь продолжаться.Иногда он не может и поэтому должен блокировать еще немного.
Лучшее эмпирическое правило заключается в том, что если есть сомнения относительно того, использовать ли проверку if
или проверку while
, всегда выбирайте * 1034.* цикл, потому что это безопаснее.Фактически, я бы довел это до крайности и предложил бы всегда использовать цикл while
, потому что нет никакого преимущества в использовании более простой проверки if
и потому что проверка if
почти всегданеправильный выбор в любом случае.Аналогичное правило справедливо для выбора: использовать Pulse
или PulseAll
.Если есть сомнения относительно того, какой из них использовать, всегда выбирайте PulseAll
.