Linux System Programming · advanced · ~14 min
Coordinate threads using a bounded queue, a mutex, and condition variables.
Producer/consumer is the classic multi-threaded design.
The queue is the meeting point where the threads synchronise.
You need four pieces:
cv_not_empty. Consumers wait on it when the queue is empty. A producer signals it with pthread_cond_signal after adding an item.cv_not_full. Producers wait on it when the queue is full. A consumer signals it after removing an item.A condition variable lets a thread sleep until another thread tells it that something changed.
while loopWait on a condition variable inside a while loop that checks the predicate (the condition you are waiting for). Do not use a plain if.
The reason is spurious wakeups: POSIX explicitly allows pthread_cond_wait to return even when no signal was sent. The while loop re-checks the condition and goes back to sleep if it is not yet true.
while (count == 0)
pthread_cond_wait(&cv_not_empty, &m);
#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. A spurious wakeup will then let a consumer dequeue from an empty buffer.not_empty after consuming an item instead of not_full.not_empty, not_full).while (predicate-not-yet-true) loop, never a plain if, to handle spurious wakeups.