A solution to Dijkstra's classic Dining Philosophers problem — exploring concurrent programming with threads and mutexes.
"This project taught me how operating systems handle concurrency — what race conditions are, how mutexes prevent them, and why the order in which threads acquire locks determines whether a program deadlocks or runs correctly. These are the exact concepts behind every multi-threaded backend, every database transaction system, and every concurrent data structure in production software."
Concurrency bugs are among the hardest to find and reproduce in production. Understanding threads, mutexes, and deadlock prevention at this level gives you the foundation to write safe, performant concurrent code in any language — Go goroutines, Java threads, Python asyncio, or Rust's ownership model all build on these same principles.
Proposed by Dijkstra in 1965, the Dining Philosophers is a classic synchronization problem:
Nphilosophers sit at a round table- Each philosopher alternates between thinking and eating
- There is one fork between each pair of adjacent philosophers
- To eat, a philosopher needs both adjacent forks
- The challenge: design a solution where no philosopher starves and no deadlock occurs
A simulation where each philosopher runs as an independent thread, with forks represented as mutexes:
- Each philosopher thread loops: think → take forks → eat → release forks → sleep
- A monitoring thread continuously checks if any philosopher has exceeded
time_to_diewithout eating - Mutexes ensure only one philosopher can hold a fork at a time
- The simulation ends when a philosopher dies or all philosophers have eaten at least
ntimes
The solution avoids deadlock by using an even/odd fork acquisition order: even-numbered philosophers pick up the right fork first, while odd-numbered ones pick up the left fork first. This asymmetry breaks the circular wait condition — the root cause of the classic deadlock scenario — without requiring a centralized arbiter or additional synchronization primitives. It's a clean, minimal, production-grade solution to a fundamental concurrency problem.
git clone https://github.com/gustavofsousa/philosophers.git
cd philosophers
make./philo num_of_philos time_to_die time_to_eat time_to_sleep [num_times_must_eat]| Argument | Description | Unit |
|---|---|---|
num_of_philos |
Number of philosophers (and forks) | — |
time_to_die |
Max time a philosopher can go without eating | ms |
time_to_eat |
Time it takes to eat | ms |
time_to_sleep |
Time a philosopher spends sleeping | ms |
num_times_must_eat |
(Optional) Stop when all have eaten this many times | — |
# No one should die
./philo 5 900 200 200
# One philosopher dies
./philo 4 310 200 200
# Stop when all philosophers have eaten at least 7 times
./philo 5 900 200 200 7- Dining Philosophers Problem — Wikipedia
- O Jantar dos Filósofos — Pantuza Blog
- How Threads Work — Pantuza Blog
- POSIX threads (
pthread_create,pthread_join,pthread_detach) - Mutex locks (
pthread_mutex_init,pthread_mutex_lock,pthread_mutex_unlock) - Race condition identification and prevention
- Deadlock avoidance strategies
- Precise timing with
usleepandgettimeofday - Concurrent state management
This project was developed as part of the 42 School curriculum.
Made with ☕ at 42 Rio de Janeiro
