Linux System Programming · advanced · ~14 min
Coordinate threads with a bounded queue, a mutex, and condition variables.
Producer/consumer is the canonical multi-threaded design: one (or many) producer threads enqueue items, one (or many) consumer threads dequeue them. The queue is the synchronisation point.
Building blocks:
cv_not_empty — consumers wait on this when the queue is empty; producers pthread_cond_signal it when they enqueue.cv_not_full — producers wait on this when the queue is full; consumers signal it when they dequeue.Always wait on a cond var inside a while loop checking the predicate, not an if. Spurious wakeups are real — POSIX explicitly allows pthread_cond_wait to return without a signal.
#include <pthread.h>
#define CAP 8
static int buf[CAP];
static int head = 0, tail = 0, count = 0;
static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t ne = PTHREAD_COND_INITIALIZER; /* not empty */
static pthread_cond_t nf = PTHREAD_COND_INITIALIZER; /* not full */
static void produce(int x) {
pthread_mutex_lock(&m);
while (count == CAP) pthread_cond_wait(&nf, &m);
buf[tail] = x; tail = (tail + 1) % CAP; count++;
pthread_cond_signal(&ne);
pthread_mutex_unlock(&m);
}
static int consume(void) {
pthread_mutex_lock(&m);
while (count == 0) pthread_cond_wait(&ne, &m);
int x = buf[head]; head = (head + 1) % CAP; count--;
pthread_cond_signal(&nf);
pthread_mutex_unlock(&m);
return x;
}
if instead of while around pthread_cond_wait. Spurious wakeups will then dequeue from an empty buffer.ne after consuming instead of nf).Producer/consumer = bounded queue + mutex + two cond vars (not_empty, not_full). Always wait inside a while (predicate-false) loop.