The first real practical example of a concurrent system.
- $N$ philosophers seated around a circular table
- one chopstick between each pair of philosophers
- a philosophers must pick up its two nearest chopsticks in order to eat
- a philosopher must pick up first one chopstick, then the second one, not both at once
![[Pasted image 20250317100456.png|100]]

**PROBLEM:** *Devise a deadlock-free algorithm for allocating these limited resources (chopsticks) among several processes (philosophers).*

#### A wrong solution
each chopstick is governed by a mutual exclusion semaphore that prevents any other philosopher from picking up the chopstick when it is already in use by another philosopher

```
semaphore chopstick[5] initialized to 1
Philosopher(i) :=
	while(1) do
		chopstick[i].down()
		chopstick[(i+1)%N].down()
		// eat
		chopstick[(i+1)%N].up()
		chopstick[i].up()
```
No two neighbors can eat simultaneously, but we can have a deadlock if all philosophers grab their right chopstick simultaneously.

#### Solution 1
Give a number to all forks and always try with the smaller.
All philosophers must first pick left and then right, except for the last one that first picks right and then left.

So there will be a contention on one fork, so this way a process is automatically excluded.

```
semaphores fork[N] all initialized at 1;
Philosopher(i) :=
	Repeat
		think;
		if (i < N-1) then
			fork[i].down();
			fork[i+1].down();
		else
			fork[0].down();
			fork[N-1].down();
		eat;
		fork[(i+1)%N].up();
		fork[i].up();
```
This is deadlock free. But not much efficient as it may happen that only a philosopher per time will have both the forks (but that is another problem).

#### Solution 3
Allow at most N-1 philosophers at a time sitting at the table

```
semaphores fork[N] all initialized at 1
semaphore table initialized at N-1

Philosopher(i) :=
	Repeat
	think;
	table.down();
	fork[i].down();
	fork[(i+1)%N].down();
	eat;
	fork[(i+1)%N].up();
	fork[i].up();
	table.up()
```
In this case we break the symmetry by letting an odd number of philosophers sit at the table at most.

#### Solution 4 - Monitors!
Pick up 2 chopsticks only if both are free
- a philosopher moves to his/her eating state only if both neighbors are not in their eating states
	- need to define a state for each philosopher
- if one of my neighbors is eating, and I’m hungry, ask them to signal me when they’re done
- thus, states of each philosopher are: thinking, hungry, eating
	- need condition variables to signal waiting hungry philosopher(s)
	
```
monitor DP
	status state[N] all initialized at thinking;
	condition self[N];

Pickup(i) :=
	state[i] = hungry;
	test(i);
	if (state[i] != eating) then
		self[i].wait;

Putdown(i) :=
	state[i] = thinking;
	test((i+1)%N);
	test((i-1)%N);

test(i) :=
	if (state[(i+1)%N] != eating
		&& state[(i-1)%N] != eating
		&& state[i] == hungry) then
			state[i] = eating;
			self[i].signal();
```
N.B.: pickup picks both forks simultaneously