Definition
Dining Philosophers Problem
The dining philosophers problem is a classic synchronisation exercise designed to illustrate challenges in avoiding deadlock and starvation in concurrent systems.
Five philosophers sit around a circular table. Each philosopher spends their time either thinking or eating. Between each pair of philosophers sits a single fork. To eat, a philosopher must acquire two forks (the ones immediately to their left and right).
Potential Problems
- Deadlock: If every philosopher picks up their left fork simultaneously, no forks will be available on the right, and everyone will wait indefinitely.
- Starvation: A philosopher might never get to eat if their neighbours alternate eating such that at least one fork is always taken.
Solutions
Solution 1: Limiting Concurrency (Counting Semaphore)
Allow at most four philosophers to sit at the table simultaneously using a counting semaphore initialised to 4. This ensures that at least one philosopher will always be able to acquire two forks.
Solution 2: Asymmetric Resource Acquisition
Instruct odd-numbered philosophers to pick up their left fork first, while even-numbered philosophers pick up their right fork first. This breaks the circular wait condition.
Solution 3: M-Semaphores (Atomic Multiple Acquisition)
Use M-Semaphores (Multiple Semaphores) to pick up both forks in a single atomic operation. The wait(S1, S2, ..., Sn) operation on an M-semaphore only proceeds if all listed semaphores are available (greater than 0). If any are unavailable, the process blocks without decompressing any values.
// Example with monitor
monitor DiningPhilosophers
enum state {THINKING, HUNGRY, EATING}
state[5] philosopher_state;
condition[5] self;
procedure pickup(i)
philosopher_state[i] := HUNGRY;
test(i);
if philosopher_state[i] != EATING then cwait(self[i]);
procedure putdown(i)
philosopher_state[i] := THINKING;
test((i+4) mod 5); // Check left neighbour
test((i+1) mod 5); // Check right neighbour
procedure test(i)
if (philosopher_state[(i+4) mod 5] != EATING and
philosopher_state[i] == HUNGRY and
philosopher_state[(i+1) mod 5] != EATING) then
philosopher_state[i] := EATING;
csignal(self[i]);