Part 7 · 1 chapters · ~8 min

Threads

pthread_create and join, shared memory and data races, mutexes, condition variables and a bounded queue, read-write locks, C11 atomics and memory ordering, thread-local storage, thread pools, and ThreadSanitizer.

8

A bounded queue with pthreads

code
typedef struct { int items[64]; int head, tail, count; pthread_mutex_t mu; pthread_cond_t not_empty, not_full; } Queue;

void push(Queue *q, int v) {
    pthread_mutex_lock(&q->mu);
    while (q->count == 64) pthread_cond_wait(&q->not_full, &q->mu);     // loop: wakeups can be spurious
    q->items[q->tail] = v; q->tail = (q->tail + 1) % 64; q->count++;
    pthread_cond_signal(&q->not_empty);
    pthread_mutex_unlock(&q->mu);
}
int pop(Queue *q) {
    pthread_mutex_lock(&q->mu);
    while (q->count == 0) pthread_cond_wait(&q->not_empty, &q->mu);
    int v = q->items[q->head]; q->head = (q->head + 1) % 64; q->count--;
    pthread_cond_signal(&q->not_full);
    pthread_mutex_unlock(&q->mu);
    return v;
}
// C11 atomics for a simple counter, no lock needed
#include <stdatomic.h>
atomic_long processed = 0;  atomic_fetch_add_explicit(&processed, 1, memory_order_relaxed);
// find races: clang -fsanitize=thread -g queue.c
THREADS AND SHARED STATE
one address space, many stacks
thread 1own stackthread 2own stackshared heap and globalsmutexone at a timecondition variablewait for a state
swipe the figure sideways, or tap expand for full screen
1/4
shared memory
Threads share the heap and globals but each has its own stack and registers. Sharing is fast and dangerous.
share everything but stacksfast and dangerous