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