diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index 83f5897..8767271 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -7,32 +7,32 @@ "id": "126da1a2d2b29212", "type": "tabs", "children": [ - { - "id": "802d9ec58484849d", - "type": "leaf", - "state": { - "type": "markdown", - "state": { - "file": "Concurrent Systems/notes/1b - Peterson algorithm.md", - "mode": "source", - "source": false - }, - "icon": "lucide-file", - "title": "1b - Peterson algorithm" - } - }, { "id": "145551a957195f29", "type": "leaf", "state": { "type": "markdown", "state": { - "file": "Concurrent Systems/notes/Lezione2.md", + "file": "Concurrent Systems/notes/2 - Fast mutex by Lamport.md", "mode": "source", "source": false }, "icon": "lucide-file", - "title": "Lezione2" + "title": "2 - Fast mutex by Lamport" + } + }, + { + "id": "fd57e934213e31db", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "Concurrent Systems/notes/1 - CS Basics.md", + "mode": "source", + "source": false + }, + "icon": "lucide-file", + "title": "1 - CS Basics" } } ], @@ -208,11 +208,12 @@ "companion:Toggle completion": false } }, - "active": "145551a957195f29", + "active": "fd57e934213e31db", "lastOpenFiles": [ + "Concurrent Systems/notes/2b - Round Robin algorithm.md", + "Concurrent Systems/notes/2 - Fast mutex by Lamport.md", "Concurrent Systems/notes/1b - Peterson algorithm.md", "Concurrent Systems/notes/1 - CS Basics.md", - "Concurrent Systems/notes/Lezione2.md", "HCIW/slides/Interface and Interaction for IoT.pdf", "Pasted image 20250305182542.png", "HCIW/notes/3 - Beacons.md", @@ -255,7 +256,6 @@ "Biometric Systems/notes/4. Face detection.md", "Biometric Systems/frequently asked questions/BS_oral_questions_16022021.md", "Biometric Systems/notes/12. Iris recognition.md", - "Biometric Systems/notes/11. Fingerprints.md", "Senza nome.canvas" ] } \ No newline at end of file diff --git a/Concurrent Systems/notes/1b - Peterson algorithm.md b/Concurrent Systems/notes/1b - Peterson algorithm.md index ae520e4..81287df 100644 --- a/Concurrent Systems/notes/1b - Peterson algorithm.md +++ b/Concurrent Systems/notes/1b - Peterson algorithm.md @@ -136,4 +136,12 @@ It satisfies MUTEX and starvation freedom. It does not satisfy bounded bypass: - when the first process wakes up, it can pass to level 2 and eventually win - but the sleep can be arbitrary long and in the meanwhile the other two processes may have entered an unbounded number of CSs -Easy to generalize to k-MUTEX. \ No newline at end of file +Easy to generalize to k-MUTEX. + +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. \ No newline at end of file diff --git a/Concurrent Systems/notes/2 - Fast mutex by Lamport.md b/Concurrent Systems/notes/2 - Fast mutex by Lamport.md new file mode 100644 index 0000000..7e8c56d --- /dev/null +++ b/Concurrent Systems/notes/2 - Fast mutex by Lamport.md @@ -0,0 +1,77 @@ +Initial idea: +``` +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 \ No newline at end of file diff --git a/Concurrent Systems/notes/2b - Round Robin algorithm.md b/Concurrent Systems/notes/2b - Round Robin algorithm.md new file mode 100644 index 0000000..38549ea --- /dev/null +++ b/Concurrent Systems/notes/2b - Round Robin algorithm.md @@ -0,0 +1,53 @@ +#### 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]] + diff --git a/Concurrent Systems/notes/Lezione2.md b/Concurrent Systems/notes/Lezione2.md deleted file mode 100644 index 5c78f08..0000000 --- a/Concurrent Systems/notes/Lezione2.md +++ /dev/null @@ -1,138 +0,0 @@ -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]] -