Esercizio - Deadlock tra due processi con lock incrociati (eserciziario, esercizi 92 e 116)
Testo (eserciziario del corso di Sistemi Operativi, Ing. Informatica UniPD, esercizi 92 e 116: lo stesso problema in due versioni). Due processi concorrenti condividono tre variabili intere e due semafori :
process foo { process bar {
z = z + 2; P(lock2);
P(lock1); y = y + 1;
x = x + 2; P(lock1);
P(lock2); x = x + 1;
V(lock1); V(lock1);
y = y + 2; V(lock2);
V(lock2); z = z + 1;
} }( = wait, = signal). Può avvenire deadlock? Come? Quali sono i valori possibili di in caso di deadlock? Teoria: Deadlock - condizioni, prevenzione, evitamento e rilevamentoUn deadlock (stallo) è una situazione in cui un insieme di processi attende all'infinito risorse possedute da altri processi dello stesso insieme; può verificarsi solo se valgono insieme quattro condizioni (mutua esclusione, hold and wait, assenza di prelazione, attesa circolare); il grafo di allocazione delle risorse (archi di richiesta P->R e di assegnazione R->P) senza cicli esclude lo stallo, con un ciclo lo implica se ogni risorsa ha una sola istanza, e lo rende solo possibile se ha più istanze; si può prevenire (negare una delle quattro condizioni, per esempio ordinare le risorse per negare l'attesa circolare), evitare (stato sicuro: esiste una sequenza sicura; algoritmo del grafo con archi di rivendicazione per istanza singola, algoritmo del banchiere con Available, Max, Allocation, Need = Max - Allocation e complessità O(m n^2) per istanze multiple), rilevare e ripristinare (grafo wait-for per istanza singola, algoritmo di rilevamento per istanze multiple; terminazione dei processi o prelazione delle risorse con scelta della vittima e rollback), oppure ignorare.Deadlock - condizioni, prevenzione, evitamento e rilevamento →, Semafori, monitor e problemi classici di sincronizzazioneUn semaforo è un intero accessibile solo con due operazioni atomiche, wait (P: aspetta finché S > 0 e decrementa) e signal (V, in POSIX sem_post: incrementa); il semaforo contatore ha valori illimitati, quello binario vale 0 o 1; con valore iniziale 1 realizza la mutua esclusione, con valore iniziale 0 impone un ordine di esecuzione (S1 prima di S2); senza attesa attiva ogni semaforo ha una coda di processi sospesi (sleep e wakeup); i semafori si usano male con facilità (ordine sbagliato, omissioni); il monitor è un tipo di dato astratto in cui un solo processo alla volta è attivo e le variabili condizione x.wait()/x.signal() sospendono e risvegliano (in POSIX mutex più pthread_cond_t); le anomalie di liveness sono deadlock, starvation e inversione di priorità; i problemi classici sono produttore-consumatore a buffer limitato (mutex, vuote = n, piene = 0; l'ordine delle wait è importante), lettori-scrittori (rw_mutex, mutex, read_count; i lettori possono far morire di fame gli scrittori) e filosofi a cena (la soluzione ingenua con un semaforo per bacchetta va in deadlock; si evita limitando a n-1 filosofi, rompendo la simmetria o ordinando le risorse), con soluzioni in C (POSIX) e in Go (canali e sync).Semafori, monitor e problemi classici di sincronizzazione →.
Svolgimento
Il deadlock è possibile. I due processi prendono i due lock in ordine opposto: foo prende e poi (con ancora tenuto), bar prende e poi (con ancora tenuto). Se foo esegue P(lock1) e bar esegue P(lock2) prima che l'altro prenda il secondo, ognuno aspetta il lock tenuto dall'altro: è la situazione dei filosofi simmetrici, un'attesa circolare. Le operazioni non c'entrano: per trovare il deadlock bisogna guardare le di semafori diversi in ordine diverso. Naturalmente i processi possono anche non andare in deadlock (se uno prende entrambi i lock prima che l'altro cominci).
Valori in caso di deadlock. Si guarda fino a dove arriva ciascun processo quando entrambi sono bloccati:
fooè bloccato suP(lock2): ha già eseguitoz = z + 2ex = x + 2(dopoP(lock1)), ma non ancoray = y + 2;barè bloccato suP(lock1): ha eseguitoP(lock2)ey = y + 1, ma nonx = x + 1néz = z + 1.
Quindi (solo foo), (solo bar), (solo foo): . È l'unico stato di deadlock possibile: finché nessuno dei due ha preso un lock, gli incrementi precedenti sono quelli fissi, e fino al punto del blocco non ci sono corse, quindi il risultato è unico (le istruzioni su variabili diverse non interferiscono). Il corso conferma: "(2,1,2); fino a quel punto non ci sono state corse, quindi il risultato è unico".
Conferma per enumerazione. Enumerando tutti gli intrecci possibili dei 7 passi di foo e dei 7 di bar, 10 sequenze finiscono in deadlock e tutte con ; gli altri intrecci arrivano alla fine con . Quindi: deadlock con oppure termine con .
Come eliminare il deadlock. Imporre lo stesso ordine di acquisizione ai due processi (sempre poi ): nega l'attesa circolare. Per esempio bar diventa P(lock1); P(lock2); y = y + 1; x = x + 1; V(lock2); V(lock1); z = z + 1;.
Domande d'esame
Il deadlock dipende dalla velocità dei processi? Come lo si evita sempre? Traccia. Dipende dall'intreccio: con un ordine di acquisizione opposto può avvenire o no. Si evita con un ordine totale dei lock.
Versione ripasso
- Codice:
foo:z+=2; P(lock1); x+=2; P(lock2); V(lock1); y+=2; V(lock2);bar:P(lock2); y+=1; P(lock1); x+=1; V(lock1); V(lock2); z+=1. Teoria: Deadlock - condizioni, prevenzione, evitamento e rilevamentoUn deadlock (stallo) è una situazione in cui un insieme di processi attende all'infinito risorse possedute da altri processi dello stesso insieme; può verificarsi solo se valgono insieme quattro condizioni (mutua esclusione, hold and wait, assenza di prelazione, attesa circolare); il grafo di allocazione delle risorse (archi di richiesta P->R e di assegnazione R->P) senza cicli esclude lo stallo, con un ciclo lo implica se ogni risorsa ha una sola istanza, e lo rende solo possibile se ha più istanze; si può prevenire (negare una delle quattro condizioni, per esempio ordinare le risorse per negare l'attesa circolare), evitare (stato sicuro: esiste una sequenza sicura; algoritmo del grafo con archi di rivendicazione per istanza singola, algoritmo del banchiere con Available, Max, Allocation, Need = Max - Allocation e complessità O(m n^2) per istanze multiple), rilevare e ripristinare (grafo wait-for per istanza singola, algoritmo di rilevamento per istanze multiple; terminazione dei processi o prelazione delle risorse con scelta della vittima e rollback), oppure ignorare.Deadlock - condizioni, prevenzione, evitamento e rilevamento →. - Deadlock: sì, lock presi in ordine opposto (attesa circolare); le sono irrilevanti.
- Valori nel deadlock:
fooferma suP(lock2)(ha fatto , ),barferma suP(lock1)(ha fatto ): , unico. Senza deadlock: . - Fix: ordine uguale ( poi ) in entrambi.
- Errori tipici: cercare il deadlock nelle ; dare valori diversi perché si contano anche le istruzioni dopo il blocco; credere che sia sempre certo.