Professional Documents
Culture Documents
Sincronizzazione Tra Processi
Sincronizzazione Tra Processi
Nei programmi concorrenti sono possibili gli errori legati ai tempi di esecuzione e di
schedulazione nella CPU che non si possono determinare ed eliminare tramite testing ma
devono essere eliminati tramite una programmazione particolarmente accurata, individuando
"dove il codice" potrebbe essere causa di possibili situazioni di errore, che quasi sempre è
connesso con la condivisione e la comunicazione di dati tra processi concorrenti.
Gli errori dipendenti dal tempo sono causati da una scorretta sincronizzazione dei processi.
Le caratteristiche degli errori dipendenti dal tempo sono:
Interleaving e Overlapping
Nella macchina con un singolo processore i processi sono "alternati nel tempo" ma con
velocità tali da dare impressione di avere un multiprocessore: in questo caso si definisce
interleaving la situazione di alternanza casuale.
Potrebbe anche esserci una situazione in cui sono presenti più macchine, ciascuna
multitasking e quindi avere una combinazione delle due situazioni sopra descritte.
Condizioni di Bernstein
Una o più aree di memoria si definisce come dominio di una istruzione o procedura, mentre
il contenuto di una o più aree di memoria si definisce come rango di una istruzione o
procedura.
I vincoli che devono soddisfare due istruzioni per essere eseguite concorrentemente sono le
condizioni di Bernstein, e le condizioni sono:
Starvation e deadlock
Un errata sincronizzazione può portare al fallimento delle elaborazioni, che genera situazioni
di:
Proprietà
Abbiamo tre diverse proprietà:
● safety: i processi non devono "interferire" tra loro nell'accesso alle risorse condivise e
i meccanismi di sincronizzazione servono a garantire la proprietà di safety;
○ Tra le molte possibili cause di errore e interferenza tra processi che possono
violare la safety ricordiamo:
○ • la presenza di corse critiche causate da una non corretta mutua esclusione;
○ • l’accesso e le azioni su stati di risorse non consistenti;
○ • la violazioni dell’atomicità di certe operazioni (lock e P() su semafori);
○ • esecuzione di azioni che dovrebbe essere proibite ma permesse dal
linguaggio di programmazione utilizzato
○ per scrivere i programmi;
○ • esecuzione di operazioni su valori e dati non aggiornati, mantenuti in cache
e quindi non consistenti.
○
● fairness: il SO deve sempre mandare in esecuzione qualsiasi processo e le richieste
di esecuzione di un processo devono essere prima o poi soddisfatte; in questo modo
viene garantita l'assenza di starvation.
● liveness: deve garantire che il processo che avanza porterà a termine in modo
corretto il proprio lavoro; è la proprietà che esclude situazioni di deadlock.
○ Tra le molte possibili cause di errore e interferenza tra processi che possono
violare la liveness ricordiamo:
○ • errori di sincronizzazione;
○ • errori con i segnali tra processi cooperanti;
○ • fallimenti di un processo: si attende un segnale da un altro processo che è
andato in crash;
○ • livelock: continuo tentativo di una azione che fallirà sempre;
○ • lockout: chiamata di una operazione che non sarà mai disponibile;
○ • esaurimento di una risorsa necessaria per evolvere.
SPIN LOCK
Per come abbiamo scritto l’istruzione di lock() non possiamo garantire l’acceso seriale a una
risorsa, in quanto potrebbe verificarsi una situazione di interleaving indesiderata.
4 quando viene risvegliato il processo P1 esegue l’istruzione che pone a rosso il semaforo
(che di fatto però è già rosso) e anch’esso utilizza la risorsa.
funzione lock(x)
inizia
ripeti // ciclo di attesa sul semaforo nel caso che sia rosso
<ritardo>
finché TestAndSet(x) // esci dal ciclo settando il semaforo a rosso
fine
funzione unlock(x)
inizia
set(x); // metti il semaforo a verde
fine
funzione P(S)
inizia
<disabilita le interruzioni>
LOCK(SX)
se S=0
allora
<poni il processo nella coda di attesa>
altrimenti
S ĸ S-1; // accedi alla risorsa
UNLOCK(SX)
<abilita le interruzioni>
fine
funzione V(S)
inizia
<disabilita le interruzioni>
LOCK(SX)
se <è presente un processo in attesa>
allora
<poni il primo processo nello stato di pronto>
S ĸ S+1; // rilascia la risorsa
UNLOCK(SX)
<abilita le interruzioni>
fine