|
philo
|
A multithreaded simulation of the classic Dining Philosophers problem.
π View on GitHub π View full documentation
This project implements a concurrent, real-time simulation of the Dining Philosophers problem using POSIX threads (pthreads) in C. Developed as part of the 42/Hive curriculum, the goal was to explore and solve common issues in parallel programming such as deadlocks, race conditions, and thread synchronization.
Philosophers alternate between thinking, eating, and sleeping, while competing for limited resources (forks). The program ensures each philosopher follows the rules safely and fairly, with careful handling of mutexes, timing, and shared state.
π Thread-Safe Synchronization All shared resources (forks, output, state) are protected with pthread_mutex_t. The simulation ensures no data race or double-access can occur β every action is guarded for correctness and consistency.
β±οΈ Accurate Timing Logic Precise delays are implemented using gettimeofday() and short polling loops to control when philosophers eat, sleep, and think β even under tight timing constraints. The system simulates real-time behavior down to the millisecond.
π¨ Deadlock & Starvation Prevention The implementation avoids deadlock by alternating fork acquisition order and managing philosopher timings, especially in edge cases like an odd number of philosophers. No philosopher is allowed to starve or monopolize forks.
π₯ Graceful Termination The system monitors each philosopher and terminates the simulation cleanly when a philosopher dies or all have completed their required meals. Mutexes are destroyed, memory is freed, and threads are joined safely.
π§© Modular and Readable Codebase Each component (init, validation, routines, monitor, utils) is clearly separated and follows consistent naming conventions. Functions are thoroughly documented with Doxygen and grouped for easy navigation.
π Educational Focus This project deepens understanding of pthread basics, critical section design, timing precision, and memory-safe multithreading.
The Dining Philosophers problem simulates a group of philosophers sitting around a table with forks placed between them. Each philosopher needs two forks to eat, one on their left and one on their right. The challenge is to design a system where philosophers can eat, sleep, and think without causing deadlocks or starvation.
Hereβs how the simulation works internally:
1. Initialization: Setting the Table Before the simulation starts:
The table is now "set" β and every philosopher has their seat and utensils.
2. Launching Threads: One Per Philosopher Each philosopher is launched in its own thread using pthread_create. Their routine loops through:
To avoid collisions on shared data (forks, output), mutexes are used to ensure synchronization.
3. Taking Forks: Safe Locking Strategy To avoid deadlocks, philosophers follow a fork-picking strategy:
This asymmetry helps prevent a circular wait, which would freeze all threads.
4. Monitoring Death: Life Clock A monitor thread (or a loop in main thread) constantly checks:
If a philosopher starves, the simulation ends, printing the time and ID of the dead philosopher. If everyone is full, it also ends cleanly.
5. Printing Actions: Thread-Safe Logging Every action (take fork, is eating, is sleeping, etc.) is logged with:
A mutex (print_padlock) ensures logs donβt overlap when multiple threads print simultaneously.
6. Exiting Cleanly When the simulation ends:
No leaks, no deadlocks, no philosophers left hanging.
π‘ Why This Works Efficiently The simulation enforces mutual exclusion using well-placed mutexes and a minimal design:
This makes the program not only robust, but predictable, deadlock-free, and easy to reason about under concurrent stress.
π οΈ To build the Philosopher simulation, simply run:
π Arguments
π§ͺ Example run
This starts the simulation with:
Each philosopher will cycle through thinking β eating β sleeping until one dies or the end of time.
π§ͺ With optional meal limit
This ends the simulation once each philosopher has eaten 7 times.
π₯οΈ Expected Output
Each log line shows:
All logs are synchronized and printed in order without overlap.
This project is licensed under the [MIT License](LICENSE).
You are free to use, modify, and distribute this code for academic, personal, or professional purposes. Attribution is appreciated but not required.
If you have any questions, suggestions, or feedback, feel free to reach out:
You're also welcome to open an issue or leave a comment on the repository.