Microsoft Docs - Windows API

Synchronization

Synchronization primitives are essential for safe communication and data sharing between threads and processes in Windows. This section provides an overview of the core IPC synchronization mechanisms, usage patterns, and example code.

Table of Contents

Overview

Windows provides several kernel‑mode and user‑mode synchronization primitives:

  • Event objects (manual‑reset & auto‑reset)
  • Mutex objects
  • Semaphore objects
  • Critical sections (user‑mode)
  • Condition variables (user‑mode)
  • Reader/Writer locks
  • Waitable timers

All these objects are waitable, meaning they can be passed to the WaitForSingleObject or WaitForMultipleObjects APIs.

Synchronization Objects

Event Objects

Events signal one or more waiting threads. They come in two types:

  • Manual‑reset: Remains signaled until explicitly reset.
  • Auto‑reset: Resets automatically after releasing a single waiting thread.

Creation API: CreateEvent. Signaling API: SetEvent, ResetEvent.

Mutex Objects

Mutexes provide mutual exclusion across processes. Only the owning thread can release the mutex.

Creation API: CreateMutex. Release API: ReleaseMutex.

Semaphore Objects

Semaphores manage a count of available resources. They can be used for producer/consumer scenarios.

Creation API: CreateSemaphore. Release API: ReleaseSemaphore.

Critical Sections

Critical sections are lightweight synchronization primitives for use within a single process.

Initialization: InitializeCriticalSection or InitializeCriticalSectionEx. Enter/Leave: EnterCriticalSection, LeaveCriticalSection.

Condition Variables

Condition variables work together with critical sections to block a thread until a particular condition becomes true.

Functions: InitializeConditionVariable, SleepConditionVariableCS, WakeConditionVariable.

Wait Functions

All the objects above can be waited on using these core APIs:

  • WaitForSingleObject
  • WaitForMultipleObjects
  • WaitForSingleObjectEx
  • WaitForMultipleObjectsEx
  • SignalObjectAndWait (atomically signal one object and wait on another)

Each function returns a wait result indicating success, timeout, or abandonment.

Example: Using a Mutex for Cross‑Process Synchronization

// Compile with: cl /EHsc mutex_example.cpp
#include <windows.h>
#include <iostream>

int main()
{
    // Create or open a named mutex
    HANDLE hMutex = CreateMutexA(
        nullptr,          // default security attributes
        FALSE,            // initially not owned
        "Global\\MySampleMutex"); // name visible to all sessions

    if (hMutex == nullptr) {
        std::cerr << "CreateMutex failed: " << GetLastError() << std::endl;
        return 1;
    }

    std::cout << "Waiting for mutex..." << std::endl;
    DWORD dwWait = WaitForSingleObject(hMutex, INFINITE);
    if (dwWait != WAIT_OBJECT_0) {
        std::cerr << "WaitForSingleObject failed: " << GetLastError() << std::endl;
        CloseHandle(hMutex);
        return 1;
    }

    std::cout << "Mutex acquired. Press Enter to release..." << std::endl;
    std::cin.get();

    ReleaseMutex(hMutex);
    CloseHandle(hMutex);
    return 0;
}
            

This program creates a named mutex that can be shared between processes. Multiple instances of the program will serialize access to the critical region.