Philosophers
The dining philosophers problem in C: threads, mutexes and starvation-free scheduling without a single data race.
The dining philosophers problem, in C, with threads and mutexes.
The problem
Philosophers sit around a table with one fork between each pair of neighbours. Eating takes two forks, so a philosopher can only eat while both neighbours are thinking. Each one runs the same cycle: take both forks, eat, put them down, sleep, think. If one goes too long without eating, they die and the simulation stops.
The program
./philo <philosophers> <time_to_die> <time_to_eat> <time_to_sleep> [meals] runs one thread per philosopher and one mutex per fork. The optional last argument stops the simulation once everyone has eaten that many times; without it, it runs until someone dies.
What it taught me
Threads, mutexes, and the discipline they demand: a data race does not show up in testing, it shows up once, hours in, on a machine that is not yours. Timing is the whole difficulty — a philosopher who dies one millisecond late is a failed project.