Правильный способ просмотра Monitor.Wait
и Monitor.Pulse
/ PulseAll
- это не средство ожидания, а (для Wait
) средство информирования системы о том, что код находится в цикл ожидания, который не может выйти до тех пор, пока что-то интересное не изменится, и (для Pulse
/ PulseAll
) как средство оповещения системы о том, что код только что изменил что-то, что может вызвать удовлетворение условия выхода цикла ожидания другого потока , Нужно иметь возможность заменить все вхождения Wait
на Sleep(0)
и все равно иметь код, работающий корректно (даже если гораздо менее эффективно, из-за того, что тратит процессорное время многократно тестируя условия, которые не изменились).
Чтобы этот механизм работал, необходимо избегать возможности следующей последовательности:
Код в цикле ожидания проверяет условие, когда оно не выполняется.
Код в другом потоке изменяет условие, так что оно выполняется.
Код в этом другом потоке запускает блокировку (которую никто еще не ждет).
Код в цикле ожидания выполняет Wait
, поскольку его условие не было выполнено.
Метод Wait
требует, чтобы ожидающий поток имел блокировку, поскольку это единственный способ убедиться, что ожидаемое условие не изменится между временем его тестирования и временем выполнения кода * 1033. *. Для метода Pulse
требуется блокировка, потому что это единственный способ убедиться, что если другой поток «обязался» выполнить Wait
, Pulse
не будет происходить до тех пор, пока другой поток фактически не сделает этого. Обратите внимание, что использование Wait
в пределах блокировки не гарантирует его правильного использования, но невозможно использовать Wait
вне блокировки.
Дизайн Wait
/ Pulse
действительно работает достаточно хорошо, если обе стороны сотрудничают. ИМХО, наибольшие слабые стороны проекта: (1) нет никакого механизма для потока, ожидающего, пока какой-либо из объектов не будет импульсным; (2) даже если кто-то «закрывает» объект таким образом, что все будущие циклы ожидания должны выходить немедленно (возможно, путем проверки флага выхода), единственный способ гарантировать, что любой Wait
, к которому потянул поток, получит Pulse
- получить замок, возможно, ожидая, пока он станет доступным.