Для меня сейчас это выглядит функционально Semaphore.WaitOne / Release
равен Monitor.Wait / Pulse
. Пропуск межпроцессных возможностей, скорость (да, монитор управляется) и другие нефункциональные различия, в чем же тогда реальная разница?
Основная цель семафора
- контролировать доступ к ограниченному набору ресурсов. Нить может участвовать в получении ресурсов, вызывая WaitOne
и Release
. Для получения ресурса нить должна вызвать WaitOne
. Однако он заблокируется только в том случае, если счетчик семафора достигнет 0, в противном случае поток может немедленно приступить к получению. Как только поток закончит, он должен вызвать Release
, чтобы сообщить семафору, что дополнительный слот был освобожден для другого потока.
Monitor.Wait
и Monitor.Pulse
кардинально отличаются. Прежде всего, здесь нет никакого подсчета. Если Pulse
вызывается в отсутствие вызова Wait
, то сигнал игнорируется и отбрасывается. Он не ставится в очередь так же, как семафор. На самом деле, поведение Wait
и Pulse
не имеет никакого внутреннего смысла. Wait
просто ожидает изменения состояния приобретенной блокировки (приобретенной от Monitor.Enter
). Pulse
- это сигнал о том, что что-то изменилось. Вот почему вы часто видите Wait
, вызываемый в цикле while
. Ожидающий поток должен повторно проверить условие ожидания, потому что он понятия не имеет, что изменилось!
Monitor.Wait
и Monitor.Pulse
являются фундаментальными механизмами синхронизации, которые могут быть использованы для формирования практически любого другого устройства синхронизации, включая семафоры.
Monitor.Wait/Pulse предоставляет вам переменную условия, которая больше похожа на событие автосброса, чем на семафор (но не совсем). Главное отличие в том, что семафор имеет счетчик, а значит, вам не нужно ничего блокировать, чтобы не пропустить импульс (в отличие от Monitor.Wait).