Mutex

A mutex (short for mutual exclusion) is a synchronization object that can be used to protect a shared resource from concurrent access by multiple threads. Only one thread can own a mutex at any given time. If a thread attempts to acquire a mutex that is already owned, the thread will block until the mutex is released.

Note: Mutexes are more heavyweight than critical sections and are typically used for synchronization across processes, although they can also be used for intra-process synchronization.

Key Concepts

Common Use Cases

Core API Functions

CreateMutex

Creates or opens a named or unnamed mutex object.

HANDLE CreateMutex(
  LPSECURITY_ATTRIBUTES lpMutexAttributes,
  BOOL                bInitialOwner,
  LPCTSTR             lpName
);
  • lpMutexAttributes: Security attributes.
  • bInitialOwner: If TRUE, the calling thread is granted initial ownership of the mutex.
  • lpName: The name of the mutex object.

Returns a handle to the mutex object or NULL on failure.

OpenMutex

Opens an existing named mutex object.

HANDLE OpenMutex(
  DWORD   dwDesiredAccess,
  BOOL    bInheritHandle,
  LPCTSTR lpName
);
  • dwDesiredAccess: Access rights.
  • bInheritHandle: Whether the handle is inheritable.
  • lpName: The name of the mutex object.

Returns a handle to the mutex object or NULL on failure.

ReleaseMutex

Releases ownership of the specified mutex object.

BOOL ReleaseMutex(
  HANDLE hMutex
);
  • hMutex: A handle to the mutex object.

Returns TRUE on success, FALSE on failure.

WaitForSingleObject (and related functions)

Waits until the specified object is in the signaled state or the time-out interval elapses. This is used to acquire the mutex.

DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD  dwMilliseconds
);
  • hHandle: A handle to the mutex object.
  • dwMilliseconds: Time-out interval in milliseconds.

Returns WAIT_OBJECT_0 if the state is signaled, WAIT_TIMEOUT if the time-out expires, or WAIT_FAILED on error.

Example Usage

The following C++ snippet demonstrates how to use a mutex to protect a shared counter:

#include <windows.h>
#include <iostream>

HANDLE hMutex;
int sharedCounter = 0;

DWORD WINAPI ThreadProc(LPVOID lpParam) {
    WaitForSingleObject(hMutex, INFINITE); // Acquire mutex

    // Critical section
    sharedCounter++;
    std::cout << "Counter: " << sharedCounter << std::endl;

    ReleaseMutex(hMutex); // Release mutex
    return 0;
}

int main() {
    hMutex = CreateMutex(NULL, FALSE, NULL); // Create a mutex

    HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
    HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);

    WaitForSingleObject(hThread1, INFINITE);
    WaitForSingleObject(hThread2, INFINITE);

    CloseHandle(hThread1);
    CloseHandle(hThread2);
    CloseHandle(hMutex);

    return 0;
}
Tip: Always ensure that you release a mutex after acquiring it, even in error conditions, to prevent deadlocks. Using RAII (Resource Acquisition Is Initialization) patterns with wrapper classes can help manage mutexes robustly.
Warning: Avoid holding mutexes for extended periods, as this can significantly impact application performance and responsiveness by blocking other threads.