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|350]] 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 How can pi enter its CS? ![[Pasted image 20250304084537.png]] ![[Pasted image 20250304084901.png]] (*must finished before nel senso che $p_i$ deve aspettare $p_j$*) ##### Deadlock freedom Let $p_i$ invoke lock - If it eventually wins -> √ - If it is blocked forever, where can it be blocked? 1. 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 after $p_i$ - let us consider the last of such $p_h \to$ it will eventually win 2. 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) - 3. In the first wait Y = ⊥ - since pj read a value different from ⊥, there is at least one pk that wrote Y before (but has not yet unlocked) - if $p_k$ eventually enters its CS -> ok, otherwise it must be blocked forever as well. Where? - In the second wait Y = ⊥: but then there exists a $p_h$ that eventually enters its CS -> good - In the ∀j.wait FLAG[j]=down: this wait cannot block a process forever ![[Pasted image 20250304090219.png]] 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 if $y = 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. - 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. ![[Pasted image 20250304093223.png]]