threads.h
POSIX pthreads work great on Linux but are not available everywhere. threads.h (C11) provides a portable threading API — thread creation, mutexes, condition variables, and thread-local storage — with a standardised interface that any conforming C11 implementation must provide.
The API surface:
| Function | Purpose |
thrd_create(t, fn, arg) | Create a thread running fn(arg) |
thrd_join(t, res) | Wait for thread, optionally get return value |
thrd_exit(code) | Exit current thread with a code |
mtx_init, mtx_lock, mtx_unlock, mtx_destroy | Mutex lifecycle |
cnd_init, cnd_wait, cnd_signal, cnd_broadcast, cnd_destroy | Condition variables |
tss_create, tss_get, tss_set, tss_delete | Thread-specific storage |
Mutex types: mtx_plain (non-recursive), mtx_recursive (same thread can lock multiple times), mtx_timed (adds mtx_timedlock).
In practice, Linux programs tend to use pthreads directly or C++ <thread>, since <threads.h> support was absent from glibc until 2022 (version 2.36). For new portable C11 code it is the right choice; for existing Linux-only code, pthreads is more common.
Practice
// compile: gcc -o thrdemo thrdemo.c -lpthread // run: ./thrdemo // description: two threads increment a shared counter under a mutex #include <threads.h> #include <stdio.h> mtx_t lock; int counter = 0; int worker(void *arg) { (void)arg; for (int i = 0; i < 100000; i++) { mtx_lock(&lock); counter++; mtx_unlock(&lock); } return 0; } int main(void) { mtx_init(&lock, mtx_plain); thrd_t t1, t2; thrd_create(&t1, worker, NULL); thrd_create(&t2, worker, NULL); thrd_join(t1, NULL); thrd_join(t2, NULL); printf("counter: %d\n", counter); // 200000 mtx_destroy(&lock); return 0; }
Remove the mtx_lock/mtx_unlock calls and run again — the counter will almost certainly land below 200000 due to the data race. This is the canonical demonstration of why shared mutable state needs synchronisation even for a single increment.
