A multithreaded solution to the classic Dining Philosophers Problem, implemented in C using POSIX threads (pthreads) and mutexes.
This project is part of the 42 School curriculum and demonstrates concurrent programming concepts including thread synchronization, mutex locks, and deadlock prevention.
- About
- The Problem
- How It Works
- Project Structure
- Requirements
- Installation
- Usage
- Example Output
- Implementation Details
- Author
The Dining Philosophers problem is a classic synchronization problem that illustrates the challenges of allocating shared resources among multiple processes without causing deadlock or starvation.
In this simulation:
- N philosophers sit around a circular table
- Each philosopher alternates between thinking, eating, and sleeping
- There are N forks on the table (one between each pair of philosophers)
- A philosopher needs two forks to eat
- If a philosopher doesn't eat within a specified time, they die
The challenge is to design a solution where:
- No philosopher starves (everyone gets to eat)
- No deadlock occurs (philosophers don't get stuck waiting forever)
- The simulation runs correctly with proper synchronization
- Initialization: Philosophers and forks (mutexes) are created based on input arguments
- Thread Creation: Each philosopher runs in their own thread
- Health Monitoring: A dedicated thread monitors if any philosopher has starved
- Fork Acquisition: Philosophers use an odd/even strategy to prevent deadlock:
- Even-numbered philosophers pick up the left fork first
- Odd-numbered philosophers pick up the right fork first
- Lifecycle Loop: Each philosopher repeats:
take forks → eat → release forks → sleep → think - Termination: Simulation ends when a philosopher dies or all have eaten the required number of meals
| File | Description |
|---|---|
philosopher.h |
Header file with struct definitions, macros, and function prototypes |
philosopher.c |
Main entry point, initialization of philosophers and simulation setup |
philosopher_utils.c |
Utility functions: ft_atoi, argument validation, time functions, ft_usleep |
actions.c |
Philosopher actions: eating, sleeping, thinking, status printing |
simulation.c |
Simulation control, health monitoring thread, thread management |
Makefile |
Build automation with standard rules |
- OS: Linux, macOS, or any POSIX-compatible system
- Compiler:
cc(GCC/Clang) with C99 support - Libraries: POSIX Threads (
pthread) - Tools:
make
Clone the repository and compile:
git clone https://github.com/itselcid/philo.git
cd philo
make| Command | Description |
|---|---|
make |
Compile the project |
make clean |
Remove object files |
make fclean |
Remove object files and executable |
make re |
Rebuild the project from scratch |
./philo number_of_philosophers time_to_die time_to_eat time_to_sleep [number_of_times_each_philosopher_must_eat]| Argument | Description |
|---|---|
number_of_philosophers |
Number of philosophers (and forks) at the table |
time_to_die |
Time in milliseconds a philosopher can survive without eating |
time_to_eat |
Time in milliseconds it takes for a philosopher to eat |
time_to_sleep |
Time in milliseconds a philosopher spends sleeping |
number_of_times_each_philosopher_must_eat |
(Optional) Simulation stops when all philosophers have eaten at least this many times |
Basic simulation with 5 philosophers:
./philo 5 800 200 200Stop after each philosopher eats 7 times:
./philo 5 800 200 200 7Edge case - single philosopher (will die):
./philo 1 800 200 2000 1 has taken a fork
0 1 has taken a fork
0 1 is eating
0 2 has taken a fork
0 2 has taken a fork
0 2 is eating
200 1 is sleeping
200 2 is sleeping
400 1 is thinking
400 2 is thinking
...
Each line shows: timestamp_in_ms philosopher_id action
has taken a forkis eatingis sleepingis thinkingdied
| Mechanism | Purpose |
|---|---|
| Mutex per fork | Ensures only one philosopher can hold a fork at a time |
| Print mutex | Prevents interleaved/garbled output from multiple threads |
| Simulation mutex | Thread-safe access to the simulation running state |
The project uses an odd/even fork acquisition order:
- Even philosophers: Pick up
left_forkfirst, thenright_fork - Odd philosophers: Pick up
right_forkfirst, thenleft_fork - Odd philosophers also start with a small delay (1ms) to reduce contention
This asymmetric approach breaks the circular wait condition that would otherwise cause deadlock.
A dedicated health_center thread continuously checks if any philosopher has exceeded their time_to_die since their last meal. If so, it prints the death message and stops the simulation.
- Uses
gettimeofday()for millisecond-precision timestamps - Custom
ft_usleep()with busy-waiting for more accurate sleep durations - Respects simulation state to exit sleep early when simulation ends
oessaadi - 42 Student
This project was created as part of the 42 School curriculum.