Semaphore

A semaphore is a kernel object used to control access to a finite number of resources. It can be used for thread synchronization, limiting concurrency, and implementing producer‑consumer scenarios.

Key Functions

Syntax Overview

// Create a semaphore
HANDLE hSem = CreateSemaphore(
    LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    LONG lInitialCount,
    LONG lMaximumCount,
    LPCTSTR lpName
);

Parameters

ParameterDescription
lpSecurityAttributesOptional security descriptor.
lInitialCountInitial count of the semaphore (>=0).
lMaximumCountMaximum count (>=lInitialCount).
lpNameOptional name for a named semaphore.

Example: Producer‑Consumer Using a Semaphore

#include <windows.h>
#include <stdio.h>

#define BUFFER_SIZE 5

HANDLE hEmptySlots;
HANDLE hFullSlots;
HANDLE hMutex;
int buffer[BUFFER_SIZE];
int in = 0, out = 0;

DWORD WINAPI Producer(LPVOID param) {
    for (int i = 0; i < 10; ++i) {
        WaitForSingleObject(hEmptySlots, INFINITE);
        WaitForSingleObject(hMutex, INFINITE);
        buffer[in] = i;
        printf("Produced: %d\n", i);
        in = (in + 1) % BUFFER_SIZE;
        ReleaseMutex(hMutex);
        ReleaseSemaphore(hFullSlots, 1, NULL);
        Sleep(100);
    }
    return 0;
}

DWORD WINAPI Consumer(LPVOID param) {
    for (int i = 0; i < 10; ++i) {
        WaitForSingleObject(hFullSlots, INFINITE);
        WaitForSingleObject(hMutex, INFINITE);
        int item = buffer[out];
        printf("Consumed: %d\n", item);
        out = (out + 1) % BUFFER_SIZE;
        ReleaseMutex(hMutex);
        ReleaseSemaphore(hEmptySlots, 1, NULL);
        Sleep(150);
    }
    return 0;
}

int main() {
    hEmptySlots = CreateSemaphore(NULL, BUFFER_SIZE, BUFFER_SIZE, NULL);
    hFullSlots  = CreateSemaphore(NULL, 0, BUFFER_SIZE, NULL);
    hMutex      = CreateMutex(NULL, FALSE, NULL);

    HANDLE hThreads[2];
    hThreads[0] = CreateThread(NULL, 0, Producer, NULL, 0, NULL);
    hThreads[1] = CreateThread(NULL, 0, Consumer, NULL, 0, NULL);
    WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
    CloseHandle(hEmptySlots);
    CloseHandle(hFullSlots);
    CloseHandle(hMutex);
    return 0;
}

This example demonstrates a classic producer‑consumer scenario where hEmptySlots and hFullSlots semaphores track buffer capacity, and a mutex protects shared data.

Comments