Dining Philosopher Problem
Problem Statement
Five philosophers sit around a circular table. Each philosopher alternates between two states:
| State | Action |
|---|---|
| Thinking | Does not interact with forks. |
| Eating | Needs two forks (left and right) to eat. |
Each philosopher must pick up their left and right forks to eat. Each fork is shared between adjacent philosophers.
Solution 1
Synchronization Primitives
| Semaphore | Initial Value | Purpose |
|---|---|---|
fork[i] | 1 | Represents availability of fork i. Only one philosopher can hold it at a time. |
Shared Data
Philosopher Process
How the Semaphores Coordinate the Processes
| Step | Semaphore Action | Effect |
|---|---|---|
| Acquire forks | wait(fork[i]) and wait(fork[(i+1)%N]) | Philosopher picks up both forks or blocks if unavailable. |
| Eat section | No conflict | Exclusive access to both forks ensures mutual exclusion. |
| Release forks | signal(fork[i]) and signal(fork[(i+1)%N]) | Makes forks available to neighbors. |
Deadlock
If all philosophers pick up their left forks simultaneously, no one can pick up their right fork — resulting in a deadlock.
| Condition | Present |
|---|---|
| Mutual Exclusion | Yes |
| Hold and Wait | Yes |
| No Preemption | Yes |
| Circular Wait | Yes |
All four Coffman conditions for deadlock are present.
Correctness Issues
| Requirement | Problem in Naive Solution |
|---|---|
| Mutual Exclusion | Satisfied via binary semaphores on forks. |
| Deadlock-Free | ❌ May deadlock if all pick left fork first. |
| No Starvation | ❌ If a philosopher is always blocked by others. |
| Concurrency | ✅ When forks are free, philosophers eat freely. |
Solution 2
To avoid deadlock and ensure progress and bounded waiting, the solution must prevent all four philosophers from holding one fork and waiting for the other.
Use a single mutex semaphore for mutual exclusion and N state flags to track each philosopher’s status. Use condition semaphores for each philosopher to avoid busy waiting.
Synchronization Primitives
| State | Meaning |
|---|---|
| THINKING | Not interested in forks |
| HUNGRY | Wants to eat (tries to pick forks) |
| EATING | Holding both forks |
Shared Data
test(i)
Check if philosopher i can eat (both neighbors are not eating).
take_forks(i)
Philosopher i wants to eat.
put_forks(i)
Philosopher i finishes eating and releases forks.
Philosopher Code
How the Semaphores Coordinate the Processes
| Issue | Resolution |
|---|---|
| Deadlock | Avoided: a philosopher only proceeds when both forks are available. |
| Starvation | Prevented by checking neighbors after every put_forks (fair wakeups). |
| Mutual Exclusion | Guaranteed: Only one philosopher accesses shared state at a time. |
| Concurrency | Enabled: Non-adjacent philosophers may eat simultaneously. |
Correctness Achieved
| Requirement | Mechanism |
|---|---|
| Mutual Exclusion | Global mutex ensures exclusive access to shared state. |
| Deadlock-Free | test() only allows eating if neighbors are not eating. |
| No Starvation | Each philosopher eventually gets a chance to eat via FIFO semaphore S[i]. |
| Concurrency | Multiple non-neighbor philosophers can eat simultaneously. |
Solution 3
Synchronization Primitives
| Semaphore | Initial Value | Purpose |
|---|---|---|
| T | 4 | Limit philosophers at the table |
| FORK | 1 | One semaphore per fork |