Mutua esclusione Sistemi Distribuiti Laurea magistrale in ingegneria informatica A.A. 2011-2012 Leonardo Querzoni
Accesso concorrente alle risorse Consideriamo un sistema in cui N processi vogliono accedere concorrentemente ad una risorsa condivisa. Ogni processo è indipendente dagli altri. I processi non si guastano. Uno scheduler sceglie di volta in volta a quale processo consentire l esecuzione della prossima istruzione. La sequenza decisa dallo scheduler, comprendente tutte le istruzioni dei diversi processi, è chiamata schedule. Solo un processo alla volta deve poter accedere alla risorsa condivisa (accesso in mutua esclusione). 2
Accesso concorrente alle risorse Ogni processo esegue un algoritmo. I processi comunicano leggendo e scrivendo variabili condivise. La lettura e scrittura di una variabile è un azione atomica (non interrompibile). Non c è alcuna assunzione sul tempo richiesto per l esecuzione di una operazione. 3
Accesso concorrente alle risorse L algoritmo è costituito da tre parti distinte: Una sottosequenza di istruzioni chiamata sezione critica. L esecuzione della sezione critica consiste nell accesso alla risorsa condivisa. Una sottosequenza di istruzioni che precedono la sezione critica, questa sequenza è chiamata trying protocol. Una sottosequenza di istruzioni che seguono la sezione critica, questa sequenza è chiamata exit protocol. 4
La mutua esclusione Dijkstra nel 1965 ha formalizzato il problema attraverso le seguenti proprietà: ME - Mutua esclusione: due processi non possono essere nelle loro sezioni critiche contemporaneamente. ND - No deadlock: se un processo rimane bloccato nel trying protocol, ci sono uno o più processi che riescono ad accedere alla sezione critica. NS - No starvation: (opzionale) nessun processo può rimanere bloccato nel trying protocol per sempre. Nota: NS implica ND. NS oltre implicare una proprietà di liveness specifica un comportamento paritetico dei vari processi (fairness). 5
Algoritmo di Dijkstra Variabili condivise: b[1,,n] : array di valori booleani inizialmente tutti posti a true c[1,,n] : array di valori booleani inizialmente tutti posti a true k : valore intero in 1,,N Variabili locali: j : valore intero 6
Algoritmo di Dijkstra Ogni processo Pi esegue il seguente algoritmo: Li0: b[i] = false Li1: if (k i) then Li2: c[i] = true if (b[k] = true) then k = i goto Li1 else Li4: c[i] = false forall j [1,,N] do if (j i c[j] = false) then goto Li1 CRITICAL SECTION c[i] = true b[i] = true (... other instructions...) goto Li0: 7
Algoritmo di Dijkstra Ogni processo Pi esegue il seguente algoritmo: Li0: b[i] = false Li1: if (k i) then Li2: c[i] = true if (b[k] = true) then k = i goto Li1 else Li4: c[i] = false forall j [1,,N] do if (j i c[j] = false) then goto Li1 CRITICAL SECTION c[i] = true b[i] = true (... other instructions...) goto Li0: Ciclo della sentinella Trying protocol Exit protocol 7
Algoritmo di Dijkstra Vediamo un possibile schedule S1 (3 processi) b[1] = false if (k 1) then c[1] = true if (b[4] = true) then P1 P2 P3 b[2] = false if (k 2) then c[2] = true b[3] = false if (k 3) then c[3] = true k = 1 goto Li1 if (k 1) then if (b[4] = true) then k = 2 goto Li1 if (k 2) then if (b[4] = true) then k = 3 goto Li1 if (k 3) then 8
Algoritmo di Dijkstra Cosa è successo? Alla fine di questa parte di schedule la situazione è la seguente: La prossima istruzione da eseguire per tutti i processi è l istruzione Li4 Il valore di k=3 A questo punto la seconda parte della trying section deve assicurare che solo uno tra P1, P2 e P3 entri in sezione critica. Sembra che P3 abbia la precedenza (perché k=3), ma in realtà l ordine di entrata lo decide lo scheduler! 9
Algoritmo di Dijkstra (prosecuzione schedule S1) P1 P2 P3 c[1] = false forall j [1,,N] do if (j 1 c[j] = false) then goto Li1 CRITICAL SECTION c[1] = true, b[1] = true c[2] = false forall j [1,,N] do if (j 2 c[j] = false) then goto Li1 CRITICAL SECTION c[2] = true, b[2] = true c[3] = false forall j [1,,N] do if (j 3 c[j] = false) then goto Li1 CRITICAL SECTION c[3] = true, b[3] = true 10
Algoritmo di Dijkstra Vediamo un possibile schedule S2 (3 processi) c[1] = false P1 P2 P3 forall j [1,,N] do if (j 1 c[j] = false) then goto Li1 if (k 1) then c[1] = true c[2] = false forall j [1,,N] do if (j 2 c[j] = false) then goto Li1 if (k 2) then c[2] = true c[3] = false forall j [1,,N] do if (j 3 c[j] = false) then goto Li1 if (k 3) then... else c[3] = false... 11
Algoritmo di Dijkstra Cosa è successo? A questo punto k=3: P1 e P2 rimangono bloccati su Li1 P3 salta alla riga Li4, pone c[3]=false ed entra in sezione critica. Quando P3 esce dalla sezione critica pone c[3] e b[3] a true sbloccando P1 e P2 12
Algoritmo di Dijkstra Proviamo la proprietà ME. Si supponga che esista uno schedule S1 tale che due processi Pi e Pj siano concorrentemente in CS: allora Pi ha eseguito con successo Li4, ossia c[j]=true. implica che Pi ha eseguito la terza linea di Li4 prima che Pj eseguisse la prima linea di Li4. quindi è anche vero che Pi ha eseguito la prima linea di Li4 prima che Pj eseguisse la prima linea di Li4. Se ora ripetiamo lo stesso ragionamento invertendo Pi e Pj: quindi è anche vero che Pj ha eseguito la prima linea di Li4 prima che Pi eseguisse la prima linea di Li4 CONTRADDIZIONE! E la struttura dati c[] che garantisce la ME. 13
Algoritmo di Dijkstra Proviamo la proprietà ND. Si supponga che un gruppo D di processi siano bloccati nella trying section e nessuno possa entrare in CS: implica che per ogni processo Pk in D b[k]=false Supponiamo che Pi sia l ultimo processo che ha fato l assegnazione della variabile k (Li3) Pi appartiene a D altrimenti se potesse eseguire la CS e l exit protocol porrebbe b[i]=true ed un altro processo Pj in D porrebbe k=j. Dato che Pj appartiene a D allora anche Pi appartiene a D. Ogni processo Pk in D avrà prima o poi c[k]=true. Ogni processo Pk in D si va quindi a bloccare nel ciclo della sentinella. 14
Algoritmo di Dijkstra Proviamo la proprietà ND. Si supponga che un gruppo D di processi siano bloccati nella trying section e nessuno possa entrare in CS: L unica eccezione è Pi che andrà in sezione critica dato che tutti i processi Pk avranno c[k]=true. Ma se Pi va in sezione critica non può appartenere a D CONTRADDIZIONE! 15
Algoritmo di Lamport Lamport nel 1974 ha proposto una nuova soluzione per lo stesso problema in un contesto diverso: I processi comunicano leggendo/scrivendo variabili condivise La lettura e la scrittura di una variabile non è un azione atomica. Uno scrittore potrebbe scrivere mentre un altro processo sta leggendo. Ogni variabile condivisa è di proprietà di un processo tutti possono leggere la sua variabile solo il processo può scrivere la sua variabile Nessun processo può eseguire due scritture contemporaneamente 16
Algoritmo di Lamport Variabili condivise: num[1,,n] : array di valori interi inizialmente tutti posti a 0 choosing[1,,n] : array di valori booleani, inizialmente tutti posti a false Variabili locali: j: valore intero compreso in 1,,N 17
Algoritmo di Lamport Ciclo ripetuto all infinito 1 NCS 2 choosing[i] = true 3 num[i] = 1 + max(num[x]: 1 x N) 4 choosing[i] = false 5 for j = 1 to N do 6 while choosing[j] do NoOp() 7 while num[j] 0 and {num[j], j} < {num[i], i} do NoOp() 8 CS 9 num[i] = 0 18
Algoritmo di Lamport Ciclo ripetuto all infinito 1 NCS 2 choosing[i] = true Doorway 3 num[i] = 1 + max(num[x]: 1 x N) 4 choosing[i] = false 5 for j = 1 to N do Bakery 6 while choosing[j] do NoOp() 7 while num[j] 0 and {num[j], j} < {num[i], i} do NoOp() 8 CS 9 num[i] = 0 18
Algoritmo di Lamport Doorway: ogni processo Pi che entra lo segnala agli altri tramite choosing[i] sceglie un numero di prenotazione pari al massimo dei numeri scelti dagli altri più 1. Altri processi concorrentemente possono accedere alla doorway 19
Algoritmo di Lamport Una possibile esecuzione della doorway: choosing[1]=true num[1]=1+max{num[j]: 1 j 3}=2 P 1 choosing[2]=true num[2]=1+max{num[j]: 1 j 3}=1 P 2 choosing[3]=true num[3]=1+max{num[j]: 1 j 3}=2 P 3 20
Algoritmo di Lamport Backery: ogni processo uscito dalla doorway deve controllare che tra i processi in attesa lui sia il prossimo ad avere accesso alla CS Il primo ciclo permette a tutti i processi che stanno nella doorway di terminare la loro scelta del numero di accesso. Il secondo ciclo lascia un processo Pi in attesa finché: il numero da lui scelto non diventa il più piccolo tutti i processi che hanno scelto un numero uguale al suo non hanno identificativo maggiore ATTENZIONE: i casi in cui viene scelto lo stesso numero di prenotazione vengono risolti basandosi sull identificativo del processo. 21
Algoritmo di Lamport Una possibile esecuzione della backery: num[1]=2 choosing[1]=false while num[j] num[1]=0 P 1 num[2]=1 choosing[2]=false while choosing[j] num[2]=0 P 2 num[3]=2 choosing[3]=false while choosing[j] while num[j] P 3 22
Algoritmo di Lamport ME deriva dalla seguente proprietà: se un processo i è nella doorway ed un processo j è nella bakery section allora {num[j], j } < {num[i],i} Se due processi i e j fossero contemporaneamente nella CS avremmo {num[i],i } < {num[j],j} e {num[j], j } < {num[i],i} che è chiaramente un assurdo NS è garantita dal fatto che nessun processo attende per sempre poiché prima o poi avrà il numero di prenotazione più piccolo. 23
Algoritmo di Lamport L algoritmo del panettiere gode anche della seguente proprietà: FCFS (First-Come-First-Served): Se Pi entra nella sezione bakery prima che Pj entri nella doorway allora Pi entrerà in sezione critica prima di Pj Domande: che valore massimo può assumere num[i]? se Pi entra nella doorway prima di Pj, allora Pi entrerà in sezione critica prima di Pj? dimostrare la proprietà FCFS 24
Modello distribuito Rispetto al modello di Lamport ora aggiungiamo un vincolo: un processo non può leggere direttamente il valore delle variabili di proprietà degli altri processi, ma per farlo deve esplicitamente inviare un messaggio ed attendere una risposta che conterrà questo valore. Ciò implica che rispetto al modello di Lamport si aggiungono le seguenti assunzioni: I processi comunicano leggendo e scrivendo variabili attraverso scambi di messaggi. Il ritardo di trasmissione di un messaggio è sconosciuto ma finito. I canali di comunicazione sono affidabili (perfect link) 25
Adattamento algoritmo di Lamport Adattamento didattico. Variabili locali: j: valore intero compreso in 1,,N choosing: valore booleano inizialmente false 26
Adattamento algoritmo di Lamport 1 NCS 2 choosing = true 3 for j = 1 to N do 4 if (j i) then 5 trigger <pp2psend Pj, getnum> 6 wait for <pp2pdeliver Pj, val> 7 num = max(num, val) 8 num = 1 + num 9 choosing = false 10 for j = 1 to N do 11 do 12 trigger <pp2psend Pj, getchoosing> 13 wait for <pp2pdeliver Pj, val> 14 while val 15 do 16 trigger <pp2psend Pj, getnum> 17 wait for <pp2pdeliver Pj, val> 18 while val 0 and {val, j} < {num, i} 19 CS 20 num = 0 27
Adattamento algoritmo di Lamport 1 NCS 2 choosing = true 3 for j = 1 to N do 4 if (j i) then 5 trigger <pp2psend Pj, getnum> 6 wait for <pp2pdeliver Pj, val> 7 num = max(num, val) 8 num = 1 + num 9 choosing = false 10 for j = 1 to N do 11 do 12 trigger <pp2psend Pj, getchoosing> 13 wait for <pp2pdeliver Pj, val> 14 while val 15 do 16 trigger <pp2psend Pj, getnum> 17 wait for <pp2pdeliver Pj, val> 18 while val 0 and {val, j} < {num, i} 19 CS 20 num = 0 Doorway Bakery 27
Adattamento algoritmo di Lamport upon event <pp2pdeliver Pi, getchoosing> do trigger <pp2psend Pi, choosing> upon event <pp2pdeliver Pi, getnum> do trigger <pp2psend Pi, num> 28
Adattamento algoritmo di Lamport Questo soluzione non è perfetta perché: In questo algoritmo il processo Pi si comporta da server rispetto alle proprie variabili num e choosing Ogni processo si limita a recuperare (leggere) i valori locali per gli altri processi con una interazione requestreply Ciò implica che: per ogni lettura abbiamo 2(N-1) messaggi scambiati; per entrare in sezione critica servono 3 scambi di messaggi (tre letture) che costano in totale 6(N-1) messaggi; 29
Adattamento algoritmo di Lamport Questo aumenta notevolmente il tempo medio necessario ad un processo per accedere alla sezione critica. Il problema deriva dal fatto che i processi non cooperano. Ogni processo agisce in modo indipendente dagli altri. Passiamo quindi ad una soluzione completamente decentralizzata. 30
Algoritmo di Ricart-Agrawala Bisogna modificare l approccio al problema: Ogni processo accede alla doorway proponendo un numero di ingresso Manda quindi una richiesta a tutti gli altri processi ed aspetta che gli altri gli concedano l accesso alla CS Ulteriori assunzione necessarie: I processi non si guastano Non si perdono messaggi Le latenza dei canali sono sconosciute ma finite 31
Algoritmo di Ricart-Agrawala Variabili locali: #replies: valore intero inizialmente pari a 0 state: valore nell insieme {requesting, CS, NCS} inizialmente pari a NCS Q: coda di richieste pendenti {T,i} inizialmente vuota Last_req: valore intero inizialmente pari a 0 Num: valore intero inizialmente pari a 0 32
Algoritmo di Ricart-Agrawala begin state = requesting num = num + 1; last_req = num; trigger <pp2psend Pj, REQUEST(last_req)>, j [1, N], j i wait until #replies = (N- 1) state = CS CS trigger <pp2psend Pi, REPLY> to any Pi Q; Q = ; state = NCS; #replies = 0 end upon event <pp2pdeliver Pj, REQUEST(t)> do if state = CS or (state = requesting and{last_req, i } < {t,j}) then Q = Q {t, j} else trigger <pp2psend Pj, REPLY> num = max(t,num) upon event <pp2pdeliver Pj, REPLY(t)> do replies++; 33
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione ;<(=>?-2'@+1A =);<( => > + > 78)9- %&,:&12'- 31%)"-)56 34
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione <=(>? @-2'A+1B >)<=( >?? +? +13"H 78)+&,191 "-) %&,:&12'- *& 7; <=(>)(-C)D'E)<=(F >(-C)D?E)GF)>)? 35
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione!7,81 9:)3%$;- -*) 17'%-%1 &7)56 + 7<(=: >-2'?+1@ =)7<( =: 7<(=: >-2'?+1@ =)7<( =: : + : +13"A 7<(=): 36
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione!"#$%&'($)*&)+&,-%'.!#%-/-"-0) 121(3&$ + <=(>8?-2'@+1A >)<=( >8 <=(>8?-2'@+1A >)<=( >8 8 + 78)+&,191 "-) %&,:&12'- *& 7; 8 8 8 +13"B <=(>)8 37
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione!"#$%&'($)*&)+&,-%'.!#%-/-"-0) 121(3&$ + 78(9: ;-2'<+1= 9)78( 9: 78(9: ;-2'<+1= 9)78( 9: : + :?;-2'<+1= @)&A)B)?'@)CAD?:@):A)B)?:@)EAD)6F : : +13"> 78(9): 38
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione!"#$%&'($)*&)+&,-%'.!#%-/-"-0) 121(3&$ 78(9: ;-2'<+1= 9)78( 9: : + 78(9: ;-2'<+1= 9)78( 9: + : 78(9(-A)B'?)78(C 78( 9(-A)B:?):C)9: :?@ : : +13"> 78(9): 39
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione 121(3&$ <=(>;?-2'@+1A >)<=( >; + E ;CD <=(>;?-2'@+1A >)<=( >; ; + ; ; ; +13"B +13"B <=(>); 78)+&,191 "-) %&,:&12'- *& 7; <=(>(-F)G'C)<=(H <=( >(-F)G;C);H)>; 40
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione 121(3&$ <=(>;?-2'@+1A >); + D ;C8 <=(>;?-2'@+1A >; + ; ; ; E?-2'@+1A C)&F)G)E'C)HFI E;C)8F)G)E;C);FI)4J ; +13"B +13"B <=(>); <=( >; 78)+&,191 "-) %&,:&12'- *& 7; 41
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione 121(3&$ <=(>;?-2'@+1A >); + D ;C8 <=(>;?-2'@+1A >; + ; ; ; +13"B ; +13"B +13"B <=(>); <=( >; 78)+&,191 "-) %&,:&12'- *& 7; 42
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione 121(3&$ <=(>? @-2'A+1B >)? + D?C8 <=(>? @-2'A+1B >? +??? E%13"&12>? +13":? +13": +13": <=(>)? <=( >? 78)+&,191 &" +13":) *- 7; 43
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione 121(3&$ <=(>8?-2'@+1A >)8 + C 8B; D%13"&12>8 <=(>8?-2'@+1A >8 + 8 8 8 D%13"&12>8 +13": 8 +13": +13": <=(>)8 <=( >8 78)+&,191 &" +13":) *- 7; 44
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione 121(3&$ <=(>8?-2'@+1A >)8 + D 8BC E%13"&12>C 56 56 <=(>8?-2'@+1A >8 + 8 8 8 E%13"&12>8 +13": 8 +13": +13": <=(>)8 <=( >8 78)+&,191 &" +13":) *- 7; 45
Algoritmo di Ricart-Agrawala Esempio di una possibile esecuzione 121(3&$ B ;< ;< A;<?%13"&12=@?%13"&12=> +13"9 +13"9?%13"&12=5 ;< ;< A;<?%13"&12=@ +13"9 7:( => 45)%&,161-7,81 &" 21,$7*$ +13"9)1) 17'%- -7,81 ":& &7) ;< 46