Другие переводы /

Semaphore Objects, Семафоры



Семафоры

Семафор – это синхронизационный объект, который поддерживает значения счетчика между нулем и установленным максимальным значением. Счетчик уменьшается на единицу каждый раз, когда поток ожидает семафор и увеличивается на единицу, когда поток освобождает семафор. Когда счетчик достигает нуля, все потоки ожидают момента, когда семафор снова будет переведен в сигнальное состояние. Семафор пребывает в сигнальном состоянии, когда его счетчик больше нуля, и недоступен (или пребывает в несигнальном состоянии) , при нулевом значении счетчика .
Семафор предназначен для контроля в ситуациях, когда общедоступный ресурс может использоваться ограниченным количеством пользователей. Он действует как клапан, который ограничивает количество потоков использующих ресурс указанным максимальным числом. Например, приложение может вмещать ограниченное количество создаваемых окон. Оно использует семафор с максимальным счетчиком равным максимальному количеству окон, уменьшает счетчик на единицу, когда окно создается и увеличивает, когда закрывается. Перед каждым созданием окна приложение должно вызывать одну из функций ожидания. Когда счетчик станет нулевым – будет указано на то, что лимит окон исчерпан – и функция ожидания заблокирует вызов кода создающего окна.
Поток использует функции CreateSemaphore или CreateSemaphoreEx для создания семафора. При создании указывается начальное значение счетчика и его максимальное значение. При создании потока также указывается имя семафора. Потоки в других процессах могут получать значние дескриптора уже существующиго семафора, по указанному имени, вызывая функцию OpenSemaphore. Больше информации о именах: мьютексов, действий (ивентов), семафоров и таймеров смотрите в статье Межпроцессорная Синхронизация.
Если больше чем один поток пребывает в ожидании семафора, то ожидающий поток будет выбран. Не применим метод выбора «первым пришел, первым обслужен» (FIFO). Внешние факторы, такие как APC режимы ядра, могут изменять порядок выбора.
Каждый раз, когда одна из функций ожидания возвращает значение, потому что семафор переключается в сигнальное состояние, счетчик семафора уменьшается на единицу. Функция Release Semaphore увеличивает счетчик семафора до определенного значения. Счетчик может никогда не стать меньше нуля или большим, чем максимальное значение.
Начальное значение семафора обычно устанавливается таким же, как и максимальное. Затем счетчик уменьшается от этого уровня, по мере того как защищенный ресурс расходуется. Кроме того, вы можете создать семафор с начальным значением равным нулю для запрета доступа к защищенному ресурсу, пока приложение не будет инициализировано. После инициализации, вы можете использовать функцию ReleaseSemaphore для увеличения счетчика до максимального значения.
Поток, который использует мьютекс, дождавшись его сигнального состояния, блокирует все внешние вызовы использующие этот же мьютекс. Поток, ожидающий семафор, уменьшает счетчик семафора на единицу каждый раз, когда операция ожидания завершается; поток будет заблокирован только тогда, когда счетчик установится в ноль. Таким образом, только поток, который использует мьютекс, может успешно вызвать функцию ReleaseMutex, и любой поток может использовать функцию ReleaseSemaphore, увеличивая счетчик семафора.
Поток может уменьшить значение счетчика семафора на единицу, больше, чем один раз повторно вызывая любые из функций ожидания. Однако, вызов одной из функции ожидания для проверки состояния нескольких объектов с массивом, который содержит несколько значений дескрипторов семафоров, не даст многократного уменьшения счетчика.
Когда вы заканчиваете использование семафора, необходимо вызвать функцию CloseHandle для уничтожения дескриптора. Семафор уничтожается, когда последний дескриптор будет закрыт. Уничтожение дескриптора не влияет на счетчик семафора; поэтому будет правильно вызвать ReleaseSemaphore перед его уничтожением или перед остановкой процесса. В противном случае, любые рассматриваемые операции ожидания по окончанию времени (по таймауту) или бесконечной продолжительности, будут продолжаться либо до окончания таймаута, либо бесконечно долго.


Semaphore Objects

A semaphore object is a synchronization object that maintains a count between zero and a specified maximum value. The count is decremented each time a thread completes a wait for the semaphore object and incremented each time a thread releases the semaphore. When the count reaches zero, no more threads can successfully wait for the semaphore object state to become signaled. The state of a semaphore is set to signaled when its count is greater than zero, and nonsignaled when its count is zero.
The semaphore object is useful in controlling a shared resource that can support a limited number of users. It acts as a gate that limits the number of threads sharing the resource to a specified maximum number. For example, an application might place a limit on the number of windows that it creates. It uses a semaphore with a maximum count equal to the window limit, decrementing the count whenever a window is created and incrementing it whenever a window is closed. The application specifies the semaphore object in call to one of the wait functions before each window is created. When the count is zero — indicating that the window limit has been reached — the wait function blocks execution of the window-creation code.
A thread uses the CreateSemaphore or CreateSemaphoreEx function to create a semaphore object. The creating thread specifies the initial count and the maximum value of the count for the object. The initial count must be neither less than zero nor greater than the maximum value. The creating thread can also specify a name for the semaphore object. Threads in other processes can open a handle to an existing semaphore object by specifying its name in a call to the OpenSemaphore function. For additional information about names for mutex, event, semaphore, and timer objects, see Interprocess Synchronization.
If more than one thread is waiting on a semaphore, a waiting thread is selected. Do not assume a first-in, first-out (FIFO) order. External events such as kernel-mode APCs can change the wait order.
Each time one of the wait functions returns because the state of a semaphore was set to signaled, the count of the semaphore is decreased by one. The ReleaseSemaphore function increases a semaphore's count by a specified amount. The count can never be less than zero or greater than the maximum value.
The initial count of a semaphore is typically set to the maximum value. The count is then decremented from that level as the protected resource is consumed. Alternatively, you can create a semaphore with an initial count of zero to block access to the protected resource while the application is being initialized. After initialization, you can use ReleaseSemaphore to increment the count to the maximum value.
A thread that owns a mutex object can wait repeatedly for the same mutex object to become signaled without its execution becoming blocked. A thread that waits repeatedly for the same semaphore object, however, decrements the semaphore's count each time a wait operation is completed; the thread is blocked when the count gets to zero. Similarly, only the thread that owns a mutex can successfully call the ReleaseMutex function, though any thread can use ReleaseSemaphore to increase the count of a semaphore object.
A thread can decrement a semaphore's count more than once by repeatedly specifying the same semaphore object in calls to any of the wait functions. However, calling one of the multiple-object wait functions with an array that contains multiple handles of the same semaphore does not result in multiple decrements.
When you have finished using the semaphore object, call the CloseHandle function to close the handle. The semaphore object is destroyed when its last handle has been closed. Closing the handle does not affect the semaphore count; therefore, be sure to call ReleaseSemaphore before closing the handle or before the process terminates. Otherwise, pending wait operations will either time out or continue indefinitely, depending on whether a time-out value has been specified.
© Все права на статью принадлежат её авторам.
Оригинал, источник: Semaphore Objects.
Перевод: Иван Игнатьев. При размещении содержимого, ссылка на источник обязательна.