OS: Semaphore Signalling
A semaphore's most powerful use isn't as a mutex, it's as a signal between threads. The trick: initialize the semaphore to 0. Now sem_wait blocks right away, until another thread calls sem_post.
That's useful when we want one thread to wait for an event from another: a result being ready, an input being available, a job finishing. Unlike a mutex where both threads "compete" for a resource, here we have a clear relationship: one waits, the other signals.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
sem_t ready;
int result;
void *compute(void *arg) {
// Do some long computation...
result = 42;
// Signal that the result is ready.
sem_post(&ready);
return NULL;
}
int main(void) {
sem_init(&ready, 0, 0); // init to 0: sem_wait blocks immediately
pthread_t worker;
pthread_create(&worker, NULL, compute, NULL);
// Wait for the worker's signal.
sem_wait(&ready);
printf("Result: %d\n", result);
pthread_join(worker, NULL);
sem_destroy(&ready);
return 0;
}
You might say: "But pthread_join does the same thing: it waits for the thread." True, and in this example pthread_join alone would be enough. Semaphores shine when we want to wait for an intermediate moment during a thread's execution (not its full termination), or when the thread runs in an infinite loop and never really ends.
Chain two semaphores together and you can synchronize two actors trading messages, a pattern called rendezvous. The producer puts a value in a shared variable, signals full, then waits for empty; the consumer waits for full, reads, then signals empty back. Both threads take turns through a single slot.
sem_t full; // init 0, signalled by producer when the slot has data
sem_t empty; // init 1, signalled by consumer when the slot is free again
That pattern is the foundation of many message queues and pipelines.
Mission: Wait for the Result
A worker thread must compute the sum of the numbers 1 through 10 and store it in a global variable. The main thread waits for the signal, then prints the result.
- Declare a semaphore
readyinitialized to 0. - The worker thread computes
1 + 2 + ... + 10and writes it into the globalsum. Then callssem_post(&ready). - The main thread calls
sem_wait(&ready), then printsSum: 55. - At the end:
pthread_joinon the worker andsem_destroyon the semaphore.
Example
Sum: 55
The output is deterministic: the main thread can't print the value until the worker has written it and signalled.
Use sem_t, sem_init, sem_wait, sem_post, sem_destroy from <semaphore.h>, and pthread_create, pthread_join from <pthread.h>.