Бөлісу құралы:


Семафор и СемафорСлим

Класс System.Threading.Semaphore представляет именованный (системный) или локальный семафор. Это тонкая оболочка вокруг объекта семафора Win32. Семафоры Win32 представляют собой подсчитывающие семафоры, которые управляют доступом к пулу ресурсов.

Класс SemaphoreSlim представляет упрощенный, быстрый семафор, который можно использовать для ожидания в рамках одного процесса, когда время ожидания, как ожидается, будет коротким. Во время фазы спин-ожидания ЦП активно работает — он не бездействует. То, насколько "коротким" должно быть ожидание, зависит от его характера: если потоки конкурируют за ресурсы процессора, ожидающий поток потребляет процессорное время, поэтому ожидание должно быть очень кратким, измеряемым в микросекундах. Если ожидание связано с ресурсом, не привязанным к ЦП (например, ввод-вывод), влияние спин-ожидания становится менее значимым, и допустимое время ожидания может быть несколько дольше, измеряемое в миллисекундах. Если время ожидания непредсказуемо или должно быть значительным, используйте System.Threading.Semaphore вместо этого, что не работает. SemaphoreSlim максимально зависит от примитивов синхронизации, предоставляемых средой CLR. Однако, при необходимости, он также предоставляет лениво инициализированные, основанные на ядре дескрипторы ожидания для поддержки ожидания нескольких семафоров. SemaphoreSlim также поддерживает использование маркеров отмены, но не поддерживает именованные семафоры или использование дескриптора ожидания для синхронизации.

Управление ограниченным ресурсом

Потоки входят в семафор, вызывая различные методы в зависимости от типа семафора. System.Threading.Semaphore Для объекта вызовите WaitOne метод (наследуемый от WaitHandle). SemaphoreSlim Для объекта вызовите SemaphoreSlim.Wait или SemaphoreSlim.WaitAsync метод. При возврате вызова значение семафора уменьшается. Если поток запрашивает доступ и счётчик равен нулю, поток блокируется. Когда потоки освобождают семафор, вызывая метод Semaphore.Release или SemaphoreSlim.Release, заблокированные потоки могут получать доступ. Нет гарантированной последовательности (например, first-in, first-out (FIFO) или last-in, first-out (LIFO)), которая определяет, какой блокированный поток входит в семафор следующим.

Поток может войти в семафор несколько раз, многократно вызывая метод объекта System.Threading.Semaphore или метод объекта WaitOne. Чтобы освободить семафор, вызовите метод Semaphore.Release() или SemaphoreSlim.Release() столько же раз, сколько поток вошел. В качестве альтернативы вызовите перегрузку Semaphore.Release(Int32) или SemaphoreSlim.Release(Int32) и укажите количество записей для выпуска.

Семафоры и идентичность потока

Два типа семафора не обеспечивают идентичность потока при вызовах методов WaitOne, Wait, Release и SemaphoreSlim.Release. Например, распространенный сценарий использования семафоров включает в себя поток производителя и поток потребителя, при этом один поток всегда увеличивает число семафоров, а другой всегда уменьшает его.

Убедитесь, что поток не освобождает семафор слишком много раз. Например, предположим, что семафор имеет максимальное значение два, и поток A и поток B входят в семафор. Если ошибка программирования в потоке B приводит к вызову Release дважды, оба вызова успешно выполняются. Счетчик семафора полон, и когда поток A в конечном итоге вызывает Release, SemaphoreFullException выбрасывается.

Именованные семафоры

Операционная система Windows позволяет семафорам иметь имена. Именованный семафор является системным — как только он создан, он доступен для всех потоков во всех процессах. Именованные семафоры могут синхронизировать действия как процессов, так и потоков.

Semaphore Создайте объект, представляющий именованный системный семафор с помощью одного из конструкторов, указывающих имя.

Это важно

Так как именованные семафоры имеют системный охват, можно иметь несколько Semaphore объектов, представляющих один и тот же именованный семафор. Каждый раз при вызове конструктора или Semaphore.OpenExisting метода создается новый Semaphore объект. Повторное указание одного и того же имени создаёт несколько объектов, представляющих один и тот же семафор.

Будьте осторожны при использовании именованных семафоров. Так как они являются системными, другой процесс, использующий то же имя, может неожиданно занять ваш семафор. Вредоносный код, выполняемый на том же компьютере, может использовать это в качестве основы атаки типа "отказ в обслуживании".

Используйте безопасность управления доступом для защиты Semaphore объекта, представляющего именованный семафор, предпочтительно с помощью конструктора, указывающего System.Security.AccessControl.SemaphoreSecurity объект. Вы также можете применить безопасность управления доступом с помощью Semaphore.SetAccessControl метода, но это оставляет окно уязвимости между созданием семафора и временем его защиты. Защита семафоров с помощью системы управления доступом помогает предотвратить вредоносные атаки, но не решает проблему непреднамеренных конфликтов имен.

См. также