This project has been created as part of the 42 curriculum by hbani-at.
Philosophers is the classic Dining Philosophers problem implemented in C using POSIX threads (pthreads) and mutexes. The simulation models N philosophers sitting around a circular table, each alternating between three states: eating, thinking, and sleeping. A shared set of N forks — one between each pair of adjacent philosophers — is the limited resource they must acquire to eat.
The goal is to design a concurrent solution that avoids deadlock (every philosopher holding one fork and waiting indefinitely for the other) and data races, while ensuring no philosopher starves. The simulation ends when a philosopher dies of starvation (i.e., exceeds time_to_die ms since their last meal) or, optionally, when all philosophers have eaten at least must_eat times.
- Thread-per-philosopher architecture — each philosopher runs in its own POSIX thread.
- Mutex-based fork protection — each fork is a
pthread_mutex_tto ensure exclusive access. - Even-odd fork acquisition — even-id philosophers pick up their right fork first, odd-id pick up their left fork first, reducing contention and breaking cyclic wait.
- Separate monitoring thread — the main thread continuously checks for death and the "all full" condition.
- Precise timing — a spin-loop
better_usleepavoids the inaccuracies ofusleep()for sub-millisecond precision. - Deadlock-free single-philosopher edge case — a single philosopher picks up the only fork and waits until death is detected.
makeThis compiles the philo executable and the internal libft library. The following targets are available:
| Target | Action |
|---|---|
all |
Build the executable |
clean |
Remove object files |
fclean |
Remove object files and executable |
re |
Full rebuild (fclean + all) |
./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 / forks on the table |
time_to_die (ms) |
Max time (ms) a philosopher can go without eating before dying |
time_to_eat (ms) |
Time (ms) a philosopher spends eating |
time_to_sleep (ms) |
Time (ms) a philosopher spends sleeping |
number_of_times_each_philosopher_must_eat (optional) |
Simulation stops once every philosopher has eaten this many times |
./philo 5 800 200 200
# 5 philosophers, 800 ms to die, 200 ms to eat, 200 ms to sleep./philo 4 410 200 200 5
# Stops when all 4 philosophers have eaten 5 times eachtimestamp_in_ms philosopher_id action
Actions:
has taken a forkis eatingis sleepingis thinkingdied
- Butenhof, D. R. (1997). Programming with POSIX® Threads. Addison-Wesley. — The definitive guide to POSIX threads programming, covering thread management, synchronization, and real-world patterns.
- Dining philosophers problem
- Kernel task_struct
- What Is a Thread in an Operating System?
- What is the difference between concurrency and parallelism?
- Threads, Mutexes and Concurrent Programming in C
- Race conditions vs Deadlocks vs Resource starvation
man pthread_create— create a new threadman pthread_join— join with a terminated threadman pthread_mutex_init— initialise a mutexman pthread_mutex_lock— lock a mutexman pthread_mutex_unlock— unlock a mutexman pthread_mutex_destroy— destroy a mutex
man gettimeofday— get the current time of day with microsecond precisionman usleep— suspend execution for microsecond intervalsman malloc— allocate dynamic memoryman free— free allocated memoryman printf— formatted output conversionman write— write to a file descriptor (used internally byft_putstr_fd)
AI was used during the development of this project for code review (identifying data-race scenarios and suggesting correct mutex placement) and optimization advice. All logic, architecture decisions, and final implementation remain the original work of the author.
philosopher/
├── Makefile # Build system
├── philo.h # Header — type definitions and function prototypes
├── main.c # Entry point, argument validation, simulation bootstrap
├── init.c # Data initialisation (forks, philosophers, mutexes)
├── routine.c # Philosopher thread routine (think, eat, sleep cycle)
├── monitoring.c # Death detection and "all full" condition checker
├── print.c # Thread-safe state printing
├── time.c # Timing utilities (get_time_ms, better_usleep)
├── error.c # Error message printing
├── cleanup.c # Resource cleanup (join threads, destroy mutexes, free)
└── libft/ # Custom libft C library
├── Makefile
├── libft.h
├── ft_atoi.c
├── ft_atol.c
├── ft_isdigit.c
└── ... (other libft functions)