Semaphores

Semaphores are synchronization objects that are used to control access to a shared resource by multiple threads. A semaphore maintains a count. Each thread that wants to access the resource must decrement the count (wait) before accessing it. If the count is zero, the thread will block until another thread increments the count (releases) the semaphore.

Key Concepts:

Core Semaphore Functions

The Windows API provides several functions for creating, manipulating, and closing semaphores.

Creating a Semaphore

The CreateSemaphore function creates a new semaphore object or opens an existing one. It returns a handle to the semaphore.

HANDLE CreateSemaphore(
    LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
    LONG lInitialCount,
    LONG lMaximumCount,
    LPCTSTR lpName
);
        

Parameters:

Opening an Existing Semaphore

The OpenSemaphore function opens an existing semaphore object.

HANDLE OpenSemaphore(
    DWORD dwDesiredAccess,
    BOOL  bInheritHandle,
    LPCTSTR lpName
);
        

Parameters:

Releasing a Semaphore

The ReleaseSemaphore function increments the count of a semaphore object. This can potentially release one or more threads that are waiting for the semaphore.

BOOL ReleaseSemaphore(
    HANDLE hSemaphore,
    LONG   lReleaseCount,
    LPLONG lpPreviousCount
);
        

Parameters:

Waiting for a Semaphore

Threads typically wait for a semaphore using the WaitForSingleObject function, passing the semaphore's handle.

DWORD WaitForSingleObject(
    HANDLE hHandle,
    DWORD  dwMilliseconds
);
        

Parameters:

Return Values:

Example Usage

Here's a simplified example illustrating the use of semaphores to limit concurrent access to a resource:

// Assuming MAX_CONCURRENT_USERS is defined
const LONG MAX_CONCURRENT_USERS = 5;
HANDLE hSemaphore = CreateSemaphore(
    NULL,              // Default security attributes
    MAX_CONCURRENT_USERS, // Initial count
    MAX_CONCURRENT_USERS, // Maximum count
    TEXT("MyResourceSemaphore") // Name
);

if (hSemaphore == NULL) {
    // Handle error
    return 1;
}

// In a thread that needs to access the resource:
DWORD waitResult = WaitForSingleObject(
    hSemaphore,  // Semaphore handle
    INFINITE     // Wait indefinitely
);

if (waitResult == WAIT_OBJECT_0) {
    // Acquired access to the resource
    // ... perform operations ...

    // Release the semaphore when done
    ReleaseSemaphore(
        hSemaphore,  // Semaphore handle
        1,           // Release one count
        NULL         // Don't need previous count
    );
} else {
    // Could not acquire access (e.g., timeout, error)
}

// In the main application thread, when the semaphore is no longer needed:
CloseHandle(hSemaphore);
        

Use Cases

Related Topics