Overview
The simulation runs continuously until one of two conditions is met:- Death Condition: A philosopher dies from starvation
- Completion Condition: All philosophers have eaten the required number of meals (if specified)
The Monitor Thread
The monitor thread is created before any philosopher threads and continuously checks for termination conditions.monitor.c:83-92
Key characteristics:
- Runs in an infinite loop
- Checks both conditions on every iteration
- Terminates immediately when either condition is met
- Sets the
dead_flagbefore returning
Death Condition
How Philosopher Death is Detected
A philosopher is considered dead when they haven’t eaten within thetime_to_die limit.
monitor.c:26-34
Death Detection Logic
The monitor checks all philosophers in sequence:monitor.c:36-54
Death Condition Requirements
For a philosopher to be declared dead, both conditions must be true:(current_time - last_meal_time) >= time_to_dieeating == 0(not currently eating)
last_meal_time yet.
Thread-Safe Death Flag
All philosopher threads check the death flag before each action:create_threads.c:15-22
This ensures:
- No race conditions when accessing the shared
dead_flag - Philosophers stop immediately when any termination condition is met
- No philosopher prints actions after death
Completion Condition
Checking Meal Count
If the optional 5th argument is provided, all philosophers must eat at least that many times.monitor.c:56-81
Completion Condition Requirements
Optional Parameter
The 5th command-line argument (
number_of_times_each_philosopher_must_eat) must be provided. If not provided, max_meal is set to -1 and this condition is never checked.All Must Finish
Every philosopher must have
meal_counter >= max_meal. If even one philosopher hasn’t finished, the simulation continues.Philosopher Thread Termination
Each philosopher thread runs a loop that checks the dead flag:create_threads.c:24-38
When dead_loop() returns 1, the philosopher thread exits its loop and returns, allowing pthread_join to proceed.
Cleanup and Resource Destruction
After all threads complete, resources are cleaned up:utils.c:46-64
Cleanup Order
Thread Joining
First, the main thread waits for the monitor thread and all philosopher threads to complete via
pthread_join.Mutex Destruction
Then
destroy_all destroys all mutexes:- Table mutexes (lock_write, lock_meal, lock_dead)
- All fork mutexes
Edge Cases
Single Philosopher
When there is only one philosopher, they will always die:philo_actions.c:28-35
Immediate Death Scenarios
Zero time_to_die
If
time_to_die is 0, philosophers die immediately as (current_time - last_meal_time) >= 0 is always true.Impossible timing
If
time_to_die < time_to_eat, philosophers will die while eating since they can’t complete a meal before the death timer expires.Too many philosophers
With many philosophers and short
time_to_die, contention for forks may cause starvation before anyone finishes eating.Max meals is 0
If
max_meal is 0, all philosophers have already “finished” and the simulation exits immediately (completion condition met).Thread Synchronization During Exit
Monitor-First Termination
The main thread joins the monitor thread before joining philosopher threads:create_threads.c:56-63
This ensures:
- The termination condition has been detected and
dead_flagis set - Philosopher threads will exit quickly after the monitor completes
- No philosopher thread outlives the monitor
Silent Message Suppression
Afterdead_flag is set, philosophers stop printing:
monitor.c:15-24
The !dead_loop(philo) check prevents:
- Messages after a philosopher dies
- Messages after all philosophers finish eating
- Interleaved output during shutdown
Summary Table
| Condition | Trigger | Message | Flag Set | Exit Code |
|---|---|---|---|---|
| Death | (time - last_meal) >= time_to_die | "<timestamp> <id> died" | Yes | 0 |
| Completion | All meal_counter >= max_meal | None | Yes | 0 |
| Thread Error | pthread_create or pthread_join fails | Writes error to stderr | N/A | Exits in destroy_all |
| Single Philo | Only 1 philosopher | "<timestamp> 1 died" | Yes | 0 |
Both normal exit conditions (death and completion) result in a clean exit with code 0. Only thread creation/join errors cause abnormal termination.