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.cTHREADS AND SHARED STATE
one address space, many stacks
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