Поделиться через


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

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

Класс SemaphoreSlim представляет упрощенный, быстрый семафор, который можно использовать для ожидания в рамках одного процесса, когда время ожидания, как ожидается, будет очень коротким. SemaphoreSlim максимально зависит от примитивов синхронизации, предоставляемых средой CLR. Однако, при необходимости, он также предоставляет лениво инициализированные, основанные на ядре дескрипторы ожидания для поддержки ожидания нескольких семафоров. SemaphoreSlim также поддерживает использование маркеров отмены, но не поддерживает именованные семафоры или использование дескриптора ожидания для синхронизации.

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

Потоки входят в семафор, вызывая метод WaitOne, который наследуется от класса WaitHandle, в случае объекта System.Threading.Semaphore, или метод SemaphoreSlim.Wait или SemaphoreSlim.WaitAsync, в случае объекта SemaphoreSlim. При возврате вызова значение семафора уменьшается. Если поток запрашивает доступ и счётчик равен нулю, поток блокируется. Затем как потоки освобождают семафор, вызывая метод 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 метода, но это оставляет окно уязвимости между созданием семафора и временем его защиты. Защита семафоров с помощью системы контроля доступа помогает предотвратить вредоносные атаки, но не решает проблему ненамеренных конфликтов имен.

См. также