4.2 KiB
Peterson's algorithm cost O(n^2)
A first way to reduce this cost is by using a tournament of MUTEX between pairs of processes:
!Pasted image 20250304082459.png
Of course this is a binary tree, and the height of a binary tree is logaritmic to the number of leaves. A process then wins after \lceil \log_{2}n \rceil
competitions \to O(\log n)
cost.
But we can do better. Let's see an idea of a constant-time algorithm.
Initialize Y at ⊥, X at any value (e.g., 0)
lock(i) :=
x <- i
if Y != ⊥ then FAIL
else Y <- i
if X = i then return
else FAIL
unlock(i) :=
Y <- ⊥
return
Problems:
- we don't want the FAIL
- it is possible to have an execution where nobody accesses its CS, if repeated forever it entails a deadlock
Initialize Y at ⊥, X at any value (e.g., 0)
lock(i) :=
* FLAG[i] <- up
X <- i
if Y ≠ ⊥ then FLAG[i] <- down
wait Y = ⊥
goto *
else Y <- i
if X = i then return
else FLAG[i] <- down
∀j.wait FLAG[j] = down
if Y = i then return
else wait Y = ⊥
goto *
unlock(i) :=
Y <- ⊥
FLAG[i] <- down
return
MUTEX proof
Deadlock freedom
Let p_i
invoke lock
- If it eventually wins -> √
- If it is blocked forever, where can it be blocked?
- In the second wait Y = ⊥
- in this case, it read a value in Y different from i
- there is a
p_h
that wrote Y afterp_i
- let us consider the last of such
p_h \to
it will eventually win
- In the ∀j.wait FLAG[j] = down
- this wait cannot block a process forever
- if
pj
doesn't lock, it flag is down - if
pj
doesn't find Y at ⊥, it puts its flag down - if pj doesn't find X at j, it puts its flag down, otherwise pj enters its CS and eventually unlocks (flag down)
- In the second wait Y = ⊥
esercizio: prova che NON soddisfa starvation freedom
From deadlock freedom to bounded bypass
-> Round Robin algorithm
Let DLF be any deadlock free protocol for MUTEX. Let's see how we can make it satisfy bounded bypass:
lock(i) :=
FLAG[i] <- up
wait (TURN = i OR FLAG[TURN] = down)
DLF.lock(i)
return
unlock(i) :=
FLAG[i] <- down
if FLAG[TURN] = down then
TURN <- (TURN + 1) mod n
DLF.unlock(i)
return
Is it deadlock free?
Since DLF is deadlock free, it is sufficient to prove that at least one process invokes DLF.lock.
If TURN = k and p_k
invoked lock, then it finds TURN = k and exits its wait.
Otherwise, any other process will find FLAG[TURN] = down
and exits from its wait.
Lemma 1: if TURN = i and FLAG[i] = up
then p_i
enters the CS in at most n-1 iterations
Observation 1: TURN changes only when FLAG[i] is down (after pi has completed its CS)
Observation 2: FLAG[i] = up -> either pi is in its CS or pi is competing for its CS -> it eventually invokes (if not already) DLF.lock
Observation 3: if p_j
invokes lock after that FLAG[i] is set, p_j
blocks in its wait
Let Y be the set of processes competing for the CS (suspended on the DLF.lock)
- because of Observation 2,
i \in Y
- because of Observation 3, once FLAG[i] is set, Y cannot grow anymore
- because DLF is deadlock free, eventually one
p_{y} \in Y
wins ify = i
.- if
y = i
we are done - otherwise, Y shrinks by one. And because of Observation 1, TURN and FLAG[TURN] don't change, so
p_y
cannot enter Y again.
- if
- Iterating this reasoning we can see that
p_i
will eventually win, and the worst case is when is the last winner.
Lemma 2: If FLAG[i] = up, then TURN is set to i in at most (n-1)^2
iterations.
If TURN=i when FLAG[i] is set, done By Deadlock freedom of RR, at least one process eventually unlocks
- If FLAG[TURN] = down, then TURN is increased. Otherwise, by Lemam 1,
p_{TURN}
wins in at most n-1 iterations and increases TURN. - If now TURN = i then we are done. Otherwise, we repeat this reasoning.
The worst case is when TURN = i+1 mod n when FLAG[i] is set.