Semaphores
Semaphores are synchronization objects that control access to a shared resource by maintaining a count. When a thread attempts to access the resource, it tries to decrement the semaphore's count. If the count is greater than zero, the thread succeeds and the count is decremented. If the count is zero, the thread blocks until another thread increments the count.
Overview
Semaphores are useful for scenarios where you need to limit the number of threads that can access a resource concurrently. For example, you might use a semaphore to limit the number of connections to a database or the number of threads that can perform a CPU-intensive operation.
Windows provides several types of semaphores:
- Counting Semaphores: These are the most common type and maintain an integer count.
- Binary Semaphores: A special case of counting semaphores where the count is either 0 or 1. They function similarly to mutexes but have different signaling behavior.
Key Functions
Core Semaphore Functions
| Function | Description |
|---|---|
CreateSemaphore |
Creates a new semaphore object, setting its initial count and maximum count. |
OpenSemaphore |
Opens an existing semaphore object by name. |
ReleaseSemaphore |
Increments the count of a semaphore object, potentially releasing one or more waiting threads. |
WaitForSingleObject / WaitForMultipleObjects |
Used to wait for a semaphore to be released (i.e., its count to become greater than zero). |
Usage Example
The following pseudocode demonstrates a basic usage pattern for a counting semaphore limiting access to a resource pool:
// Assume a semaphore with an initial count of 5 (allowing 5 concurrent accesses)
HANDLE hSemaphore = CreateSemaphore(NULL, 5, 5, L"ResourcePoolSemaphore");
if (hSemaphore != NULL) {
// Thread attempts to acquire access
DWORD dwWaitResult = WaitForSingleObject(hSemaphore, INFINITE);
if (dwWaitResult == WAIT_OBJECT_0) {
// Access the shared resource (e.g., a connection from the pool)
// ... do work ...
// Release the resource and signal the semaphore
// The second parameter indicates how much to increase the count by
ReleaseSemaphore(hSemaphore, 1, NULL);
} else {
// Handle error
}
CloseHandle(hSemaphore);
}
Considerations
- Ownership: Unlike mutexes, semaphores do not have an owner. Any thread can call
ReleaseSemaphoreto increment the count, even if it didn't originally decrement it. - Deadlocks: Improper use of semaphores can lead to deadlocks, especially when multiple semaphores are involved. Always acquire semaphores in a consistent order to prevent this.
- Maximum Count: Ensure the maximum count is set appropriately to avoid excessive resource consumption or insufficient access.
- Naming: Named semaphores can be shared across processes. Use unique and descriptive names.
For detailed information on each API function and advanced scenarios, please refer to the official Windows API documentation.