Esercizio - Conteggio dei valori finali con una variabile condivisa (eserciziario, esercizi 96 e 112)
In questa pagina 3
Esercizio 96. Pseudo-codice:
const int n = 20;
int conta;
void incrementa() {
int i;
for (i = 0; i < n; ++i) {
int t;
t = conta;
conta = t + 1;
}
}
void main() {
conta = 0;
parbegin(incrementa, incrementa); /* due processi concorrenti */
write(conta);
}parbegin avvia due processi concorrenti che incrementano iterativamente una variabile condivisa; la velocità relativa dei due processi non è prevedibile. (1) Quali sono i valori minimo e massimo che il risultato può assumere e perché? (2) Quali sono se vengono avviati processi invece di 2?
Esercizio 112. Due thread eseguiti in concorrenza con memoria condivisa:
Thread A: Thread B:
for (i = 0; i < 5; i++) for (j = 0; j < 5; j++)
x = x + 1; x = x + 2; è inizializzata a 0. Si suppone che x = x + 2 nel thread sia atomica (come una funzione atomicIncr2(x)); questo non vale per x = x + 1 del thread . Quali sono i possibili valori finali di ?
Esercizio 96
Ogni iterazione fa t = conta; (lettura) e conta = t + 1; (scrittura): se due processi si intrecciano, uno può scrivere un valore basato su una lettura vecchia e cancellare gli incrementi dell'altro (aggiornamento perso, Sincronizzazione - sezione critica, race condition e mutexQuando più processi o thread accedono agli stessi dati e il risultato dipende dall'ordine degli accessi si ha una race condition (esempio: counter++ e counter-- sono tre istruzioni macchina ciascuna, e interleaving diversi danno 4, 5 o 6 partendo da 5); il problema della sezione critica chiede un protocollo (entry section, sezione critica, exit section, remainder section) che garantisca mutua esclusione, progresso e attesa limitata; disabilitare gli interrupt non scala sui multiprocessori, l'alternanza stretta con turn viola il progresso, la soluzione di Peterson (flag[2] e turn) soddisfa i tre requisiti ma può fallire su hardware moderno per il riordino delle istruzioni, per cui servono barriere di memoria; l'hardware offre test_and_set e compare_and_swap (atomiche) e variabili atomiche; il mutex lock (acquire/release, in POSIX pthread_mutex_t) è lo strumento di alto livello, con attesa attiva se è uno spinlock oppure con sospensione del thread se è un mutex di sistema; bloccare due volte lo stesso mutex senza sbloccarlo causa deadlock.Sincronizzazione - sezione critica, race condition e mutex →).
Massimo: (con : 40). Si ottiene quando nessun incremento va perso, per esempio quando i processi si eseguono uno dopo l'altro: ogni incremento viene contato.
Minimo: 2, anche per processi qualsiasi con almeno 2 (non 20: la soluzione del corso riporta 20, ma è un errore: scrive che il minimo corrisponde a "una interruzione a ogni iterazione e sarà ovviamente pari a 20", e per processi indica 20 come minimo e come massimo. Il minimo reale è 2). Costruzione per due processi e con :
- legge
conta(0) inte si ferma; - esegue iterazioni complete:
contavale 19; - scrive
conta = 0 + 1 = 1(cancella 19 incrementi); poi si ferma; - legge
conta(1) per la sua ultima iterazione e si ferma; - esegue le sue 19 iterazioni rimaste:
contavale 20; - scrive
conta = 1 + 1 = 2. Ora ha finito (20 iterazioni) e pure: risultato 2.
Perché non si può scendere sotto 2: ogni scrittura scrive (con ), quindi dopo la prima scrittura conta vale sempre almeno 1. Il processo che termina per ultimo termina con la sua ventesima scrittura, che è l'ultima di tutte; la sua ventesima lettura avviene dopo la sua diciannovesima scrittura, quindi legge un valore e scrive . La verifica esaustiva (enumerazione di tutti gli intrecci) conferma: per due processi con il risultato minimo è 2 e il massimo 40; per processi con minimo 2 e massimo 15 (stessa legge: minimo 2, massimo ).
| minimo | massimo | |
|---|---|---|
| 2 processi, | 2 (il corso dice 20) | 40 |
| processi, | 2 (il corso dice 20) |
Esercizio 112
Il thread aggiunge 2 in modo indivisibile, 5 volte: contributo totale 10. Il thread fa 5 volte x = x + 1, ognuna composta da lettura e scrittura. Le sole interferenze possibili: legge , poi esegue delle sue somme (atomiche) e infine scrive (letto ): le somme di avvenute nella finestra tra la lettura e la scrittura di vengono cancellate.
Quindi , dove è il numero totale di somme di cancellate (0 ):
| 0 | 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|---|
| finale | 15 | 13 | 11 | 9 | 7 | 5 |
Valori possibili: 5, 7, 9, 11, 13, 15. Esempi: 15 se i thread non si intrecciano; 5 se legge 0, fa tutte e 5 le somme () e poi scrive 1 (i 5 incrementi di sono cancellati), seguono 4 incrementi di . Valori pari o maggiori di 15 sono impossibili. Verificato enumerando tutti gli intrecci: l'insieme dei valori è esattamente , come nel corso.
Domande d'esame
Con 2 processi che incrementano 20 volte una variabile condivisa senza mutua esclusione, qual è il valore minimo? Traccia. 2 (non 20): un processo legge 0 presto, l'altro fa 19 giri, il primo scrive 1, poi il secondo legge 1 e il primo fa i suoi 19 giri, infine il secondo scrive 2.
Versione ripasso
- 96: due processi,
t = conta; conta = t + 1;per 20 volte. Massimo ( processi), minimo 2 (il corso scrive 20: errore). Teoria: Sincronizzazione - sezione critica, race condition e mutexQuando più processi o thread accedono agli stessi dati e il risultato dipende dall'ordine degli accessi si ha una race condition (esempio: counter++ e counter-- sono tre istruzioni macchina ciascuna, e interleaving diversi danno 4, 5 o 6 partendo da 5); il problema della sezione critica chiede un protocollo (entry section, sezione critica, exit section, remainder section) che garantisca mutua esclusione, progresso e attesa limitata; disabilitare gli interrupt non scala sui multiprocessori, l'alternanza stretta con turn viola il progresso, la soluzione di Peterson (flag[2] e turn) soddisfa i tre requisiti ma può fallire su hardware moderno per il riordino delle istruzioni, per cui servono barriere di memoria; l'hardware offre test_and_set e compare_and_swap (atomiche) e variabili atomiche; il mutex lock (acquire/release, in POSIX pthread_mutex_t) è lo strumento di alto livello, con attesa attiva se è uno spinlock oppure con sospensione del thread se è un mutex di sistema; bloccare due volte lo stesso mutex senza sbloccarlo causa deadlock.Sincronizzazione - sezione critica, race condition e mutex →. - Schedule per il minimo 2: legge 0; fa 19 giri (conta=19); scrive 1; legge 1; fa 19 giri (conta=20); scrive 2.
- 112: : 5 volte
x=x+1(non atomico); : 5 voltex=x+2(atomico): , = somme di cancellate (0..5): 5, 7, 9, 11, 13, 15. - Metodo: scrivere
t=conta; conta=t+1come due passi; gli incrementi persi sono quelli fatti tra lettura e scrittura di un altro. - Perché non meno di 2 (96): ogni scrittura è , quindi
contadopo la prima scrittura; l'ultima scrittura è la ventesima di un processo, la cui lettura avviene dopo la sua diciannovesima scrittura: legge e scrive . Enumerazione esaustiva: 2 processi min 2, max 40; 3 processi min 2, max 15. - Perché 112 dà numeri dispari (112): parte da ; ogni somma di cancellata da una scrittura di toglie 2.
- Errori tipici: minimo 20 invece di 2; contare 0 come valore possibile in 112; dimenticare che
x=x+2atomica non può essere "spezzata".