Esercizio - Output ed ordine di esecuzione con i semafori (eserciziario, esercizi 6, 7 e 8)
In questa pagina 4
Esercizio 6. Risorse condivise: semafori e int x = 100.
Processo P1: Processo P2: Processo P3:
wait(S); wait(T); wait(U);
if (x == 0) x := x - 1; x := x + 1;
signal(T); signal(S); signal(S);
else
signal(U);
wait(S);
write(x);I tre processi girano concorrentemente sulla stessa CPU. Qual è l'output con , , ? Se invece i semafori fossero inizializzati a , , , si può avere una race condition?
Esercizio 7. Semafori .
process P1 { process P2 {
signal(s1); signal(s2);
wait(s2); wait(s1);
print "P"; print "A";
wait(s2); signal(s2);
print "R"; wait(s1);
signal(s1); print "I";
} }Descrivere il comportamento e i possibili output dell'esecuzione parallela di e .
Esercizio 8. Semafori e int x = 0.
Processo P1: Processo P2: Processo P3:
while (1) { while (1) { wait(U);
wait(S); wait(T); while (1) {
wait(M); wait(M); wait(M);
x = x + 1; write(x); x = 0;
signal(M); signal(M); signal(M);
signal(T); signal(S); }
} }Qual è l'output se i semafori sono inizializzati (1) ; (2) ; (3) ? Qual è il ruolo del semaforo ?
Esercizio 6
Con :
| passo | chi | azione | ||||
|---|---|---|---|---|---|---|
| 0 | stato iniziale | 1 | 0 | 0 | 100 | |
| 1 | wait(S): passa |
0 | 0 | 0 | 100 | |
| 2 | x == 0? no, quindi signal(U) |
0 | 0 | 1 | 100 | |
| 3 | wait(U) passa, x = x + 1 |
0 | 0 | 0 | 101 | |
| 4 | signal(S) |
1 | 0 | 0 | 101 | |
| 5 | secondo wait(S) passa, write(x) |
0 | 0 | 0 | 101 |
resta bloccato per sempre su wait(T) ( non viene mai incrementato). Output: 101. "risveglia" , che incrementa e a sua volta "risveglia" .
Con . si blocca subito su wait(S). Invece (per ) e (per ) possono entrambi avanzare: modificano senza nessun semaforo comune che li escluda a vicenda ( e sono semafori diversi e sono entrambi "aperti"). Quindi sì, c'è una race condition su : x = x - 1 e x = x + 1 sono sequenze lettura-modifica-scrittura intrecciabili, e il risultato può essere 99, 100 o 101 (aggiornamento perso). Chi segnala per primo (uno dei due) sveglia , che stampa un valore che dipende dall'intreccio; il secondo signal(S) lascia a 1 e il secondo wait(S) di passa senza aspettare che l'altro processo abbia finito.
Esercizio 7
Traccia (le due sequenze iniziali sono concorrenti):
- esegue
signal(s1)(); eseguesignal(s2)(), in qualunque ordine. - fa
wait(s2): passa (); fawait(s1): passa (). - stampa P, stampa A: l'ordine tra queste due è libero.
- fa il secondo
wait(s2): , si blocca; fasignal(s2), dopo aver stampato A. Ora passa e stampa R. - esegue
signal(s1); solo allora passa il secondowait(s1)e stampa I.
Perciò R viene dopo A e dopo P, e I viene dopo R: gli unici output possibili sono PARI e APRI. Enumerando tutti gli intrecci possibili con un programma (stato dei semafori e posizione di ogni processo) si trovano esattamente queste due stringhe e nessun deadlock.
Esercizio 8
Il semaforo è un mutex (valore 1): protegge l'accesso alla variabile condivisa da parte dei tre processi. e fanno alternare e (un incremento, una stampa, un incremento...): aspetta e segnala ; aspetta e segnala ; abilita l'azzeramento di .
- . parte: ,
signal(T); stampa 1,signal(S); : ; ... è bloccato per sempre suwait(U). Output: 1 2 3 4 ... (sequenza infinita dei naturali da 1). - . Parte : stampa ,
signal(S); poi incrementa a 1 e segnala ; stampa 1. Output: 0 1 2 3 .... - . può girare: quando riesce a prendere azzera (), quindi la sequenza viene azzerata in momenti non deterministici: l'output è del tipo con (se la sotto-sequenza è vuota). Esempi:
0 0 0 ...(azzera sempre prima di ogni stampa),1 1 1 ...,0 1 2 0 1 2 3 .... Il mutex garantisce solo che gli accessi a non si sovrappongano, non l'ordine.
Domande d'esame
Perché in 6 con c'è una race condition e con no? Traccia. Nel secondo caso solo e poi toccano , uno dopo l'altro (i semafori impongono l'ordine); nel primo e sono entrambi abilitati e nessun semaforo comune ne protegge l'accesso.
Versione ripasso
- 6 (): con :
wait(S),signal(U); : ,signal(S); stampa 101; bloccato su . Con : e modificano insieme (semafori diversi, entrambi aperti) race condition (99, 100 o 101). Teoria: 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 →. - 7 (): P e A in qualunque ordine, poi R (dopo il secondo
wait(s2)), poi I (doposignal(s1)): PARI o APRI. - 8: = mutex su ; alternano ; abilita . (1) 1 2 3 ...; (2) 0 1 2 3 ...; (3) azzeramenti non deterministici: .
- Metodo: tabella passo-passo con i valori dei semafori; un semaforo a 0 blocca, a 1 lascia passare uno.
- 6, tabella (): : (), : (
signal(U)), : (), : (), : ( secondawait),write(101). - 7, tracce: dopo i due
signaliniziali;wait(s2)di ewait(s1)di passano e portano a 0; P e A in qualunque ordine; il secondowait(s2)di resta bloccato finché (dopo A) fasignal(s2); R, poisignal(s1)di sblocca la secondawait(s1)di : I. Enumerazione di tutti gli intrecci: soloPARIeAPRI, nessun deadlock. - 8, ruoli: mutex su (valore 1); e alternano e (un incremento, una stampa); abilita ad azzerare (azzeramento dopo che passa
wait(U): non deterministico). - Errori tipici: dimenticare che resta bloccato per sempre (6); contare PARI e APRI come gli unici ordini senza spiegare perché; confondere mutex e ordine.