C11 Multithreading: Guide to threads.h
Prior to the C11 standard, the C programming language lacked native
multithreading support, requiring developers to rely on operating
system-specific APIs such as POSIX Threads (pthreads) on Unix-like
systems or the Win32 threading API on Windows. With the release of
ISO/IEC 9899:2011 (commonly known as C11), native multithreading was
integrated directly into the C language specification through the
standard library header <threads.h>. This article
explains the background of C11 threads, outlines the primary components
provided by <threads.h>, and details how to utilize
its core synchronization and execution primitives.
The Introduction of Standard Threads in C11
The multithreading library introduced in C11 is defined under the
<threads.h> header. Its design is largely a
simplified, platform-agnostic adaptation of the POSIX threads API,
designed to provide a consistent threading interface across different
operating systems.
C11 designates multithreading as an optional language feature.
Conforming implementations that do not support standard multithreading
define the macro __STDC_NO_THREADS__ with a value of
1. Compilers and standard C libraries supporting the
feature do not define this macro and make <threads.h>
available out of the box.
Core Components of
<threads.h>
The C11 threading model organizes concurrent operations into four main areas: thread lifecycle management, mutual exclusion (mutexes), condition variables, and thread-specific storage.
1. Thread Management
Thread execution is handled using the thrd_t type and
functions prefixed with thrd_:
thrd_create: Spawns a new thread that executes a function matching the signatureint (*)(void *).thrd_join: Blocks the calling thread until the designated thread terminates, retrieving its integer return code.thrd_detach: Disconnects a thread so its resources are reclaimed automatically upon completion, without requiring a join.thrd_exit: Terminates the calling thread immediately with a specified result code.thrd_current: Returns thethrd_tidentifier of the currently executing thread.thrd_sleep: Suspends thread execution for a specified duration usingstruct timespec.
2. Mutexes
Mutual exclusion primitives use the mtx_t type to
prevent data races on shared data:
mtx_init: Initializes a mutex. Flags can configure the mutex behavior, such asmtx_plain,mtx_timed, ormtx_recursive.mtx_lock: Blocks until the mutex is acquired.mtx_trylock: Attempts to acquire the mutex without blocking, returningthrd_busyif unavailable.mtx_unlock: Releases ownership of the mutex.mtx_destroy: Frees resources allocated to the mutex.
3. Condition Variables
Signaling between threads is managed with condition variables using
the cnd_t type:
cnd_init: Initializes the condition variable.cnd_wait: Atomically unlocks a specified mutex and waits until signaled.cnd_signal: Unblocks at least one thread waiting on the condition variable.cnd_broadcast: Unblocks all threads currently waiting on the condition variable.cnd_destroy: Cleans up the condition variable.
4. Thread-Specific Storage (TSS)
Thread-specific data storage allows threads to maintain separate
values under a shared identifier using tss_t:
tss_create: Creates a storage key, optionally binding a destructor function invoked at thread termination.tss_set: Sets the thread-local pointer value associated with the key.tss_get: Retrieves the thread-local pointer value for the key.tss_delete: Destroys the storage key.
Integration with C11 Memory Model
Alongside <threads.h>, C11 introduced the memory
model and atomic operations library under
<stdatomic.h>. This standard memory model formally
defines data races, synchronization points, and memory ordering
semantics (memory_order_relaxed,
memory_order_acquire, memory_order_release,
and memory_order_seq_cst). The combination of standard
threads and atomic primitives allows portable, lock-free, and
thread-safe systems programming natively in C.