Linux System Programming · intermediate · ~25 min
Spawn threads, share state safely with a mutex, and coordinate threads with a condition variable.
POSIX threads (pthreads) create lightweight execution contexts that all share the same memory.
Because threads share memory, you must protect shared data:
Multi-threaded C is everywhere:
Pthreads is the standard threading API for the C language.
pthread_create(&tid, attr, fn, arg) starts a new thread.pthread_join(tid, &ret) waits for that thread to finish and collects its return value.A mutex (mutual-exclusion lock) ensures only one thread runs a critical section at a time.
pthread_mutex_lock / pthread_mutex_unlock mark the start and end of the protected region.PTHREAD_MUTEX_INITIALIZER initializes a mutex statically.A condition variable lets a thread wait for something to become true.
pthread_detach(tid) means: "I don't need this thread's return value; reclaim its resources as soon as it exits."
Race conditions in concurrent code become real CVEs.
A "check then act" sequence shared across threads without a mutex is a TOCTOU (time-of-check to time-of-use) bug at the thread level.
pthread_* functions.pthread_mutex_destroy during teardown.#include <pthread.h>
int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*fn)(void *), void *arg);
int pthread_join(pthread_t tid, void **retval);
int pthread_mutex_lock(pthread_mutex_t *m);
int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m);
POSIX threads (pthreads) are the standard C concurrency API on Linux.
The core operations are:
pthread_create.pthread_join.pthread_mutex_t.pthread_cond_t.pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
int counter = 0;
void *bump(void *_) {
pthread_mutex_lock(&m);
counter++;
pthread_mutex_unlock(&m);
return NULL;
}
pthread_t t;
pthread_create(&t, NULL, bump, NULL);
pthread_join(t, NULL);
pthread_mutex_lock(&m); /* acquire */
while (!queue_has_data(q)) /* spurious wakeups exist */
pthread_cond_wait(&c, &m); /* atomic release + wait */
item_t x = queue_pop(q);
pthread_mutex_unlock(&m); /* release */
use(x);
-fsanitize=thread) finds data races at runtime.info threads lists all threads; thread N switches to thread N.All threads share the heap.
volatile is not a substitute for a mutex or an atomic. It does not provide thread safety.C-language concurrency appears almost everywhere:
pthread_once for one-shot initialization.