Classroom
Classroom
concorrente
Introduzione alla programmazione concorrente
Programmazione concorrente
Concetti fondamentali
● Programma: è un insieme di istruzioni che descrive le azioni
da compiere.
● Processo: rappresenta l’esecuzione delle azioni specificate
dal programma; un processo in esecuzione può cambiare il
proprio stato.
● Processore: è un dispositivo che consente l’evoluzione e il
completamento di un processo (la CPU). In
multiprogrammazione ogni utente ha l’impressione di
lavorare con un suo processore virtuale.
Programmazione concorrente
● Thread: è un segmento di istruzioni di un processo in
esecuzione. Un processo è un insieme di Thread che
rappresentano il suo codice eseguibile. Un processo è
composto come minimo da un thread, ma normalmente a
ogni processo ne vengono associati più di uno in base alle
capacità di avanzamento concorrente di ciascuno.
● Risorse del sistema: è un qualsiasi elemento hardware o
software che viene usato da un processo e che ne condiziona
la creazione o l’avanzamento.
Programmazione concorrente
Gestione delle risorse
Le risorse possono essere:
● prerilasciabili:
○ si possono sottrarre al processo che le sta usando prima
che esso le abbia rilasciate e senza causare il fallimento
della sua esecuzione;
○ il loro stato non si modifica durante l’utilizzo e può essere
salvato e successivamente ripristinato;
● non prerilasciabili:
○ non si possono sottrarre al processo che le sta usando
senza causarne il fallimento;
○ il loro stato non può essere salvato e ripristinato.
Programmazione concorrente
Per gestire la programmazione concorrente il sistema operativo
deve prevedere:
● un gestore della risorsa;
● un protocollo di accesso alla risorsa:
○ richiesta e assegnazione della risorsa;
○ utilizzo della risorsa;
○ rilascio della risorsa.
Programmazione concorrente
Programmi sequenziali e concorrenti
I programmi si possono classificare in sequenziali e
concorrenti: nel primo caso, l’esecuzione di un programma dà
luogo a un singolo processo, svolge una sola istruzione alla volta
sulla base di un programma sequenziale. Nel secondo caso, dà
luogo a più processi che competono tra loro per l’uso delle
risorse del sistema, vengono eseguite più istruzioni
contemporaneamente.
Da un punto di vista funzionale non vi è differenza tra i due tipi
di programmazione. I programmi concorrenti devono però fare
in modo che i vari processi si sincronizzino tra loro.
Programmazione concorrente
Processi concorrenti
I programmi concorrenti prevedono la creazione di più
processi (thread) che comunicano tra loro, si sincronizzano e
competono tra loro per le risorse di sistema.
Programmazione concorrente
In figura vediamo il processo P0 che
passa il controllo al processo P1, il
quale, quando ha terminato, restituisce
il controllo a P0.
Programmazione concorrente
Team di lavoro
In figura viene illustrato un’analogia
tra il mondo reale e un sistema di
elaborazione. Gli obiettivi si
raggiungono solo se i vari componenti
del team collaborano tra loro.
In generale si devono:
● pianificare le varie fasi di lavoro;
● coordinare le attività dei
componenti del team;
● predisporre le risorse necessarie;
● evitare conflitti per l’accesso a
eventuali risorse condivise.
Programmazione concorrente
Grafo delle precedenze
Processi paralleli
Per poter svolgere le attività in modo coerente, è opportuno
descrivere come i vari processi sono legati tra loro da rapporti
di precedenza tramite il grafo delle precedenze.
Si tratta di un grafo orientato in cui in ogni nodo viene
rappresentato un blocco di istruzioni, mentre le frecce indicano
la dipendenza di un blocco da un altro.
Programmazione concorrente
Per capire meglio il concetto
vediamo come esempio la
somma di 2 numeri.
Inizia
Leggi A
Leggi B
Calcola T = A + B
Stampa T
Fine
In figura è rappresentata la
sequenza delle operazioni (A) e
quella in cui si evidenziano le
attività parallele (B).
Programmazione concorrente
Programmazione concorrente
Programmazione concorrente
Grafo delle precedenze
Programmazione concorrente
Esecuzione concorrente di processi
Programmazione concorrente
Creazione ed eliminazione di processi
Programmazione concorrente
Notazione cobegin/coend
Esiste un costrutto linguistico utilizzato per la descrizione di
esecuzioni concorrenti:
cobegin
S1(...)
S2(...)
....
Sn(...)
coend
Programmazione concorrente
I processi possono essere più o meno “consapevoli” uno della
presenza dell’altro. Possono esistere infatti processi totalmente
“ignari” uno dell’altro, non progettati per lavorare insieme ma
che operano in un ambiente comune.
Se questi necessitano delle stesse risorse, si troveranno a
interferire tra loro, e sarà compito del sistema operativo
gestirli fornendo gli opportuni meccanismi di sincronizzazione.
Programmazione concorrente
L’ordine con cui due processi accedono a una risorsa condivisa
è importante perché, nel caso di dati condivisi, determina la
consistenza dei dati (race condition). La condizione impone
che un solo processo alla volta possa modificare i dati.
Il sistema operativo deve quindi gestire questa condizione
garantendo che:
● vi sia mutua esclusione, nel senso che se un processo sta
utilizzando una risorsa nessun altro processo può
appropriarsene;
● un processo che voglia accedere a una risorsa debba
attendere un tempo finito;
● non si verifichi la condizione di stallo: cioè che un processo
si blocchi in attesa di una risorsa che non potrà ottenere.
Programmazione concorrente
Competizione e cooperazione tra processi
L’interazione tra processi può essere di tipo:
● competitivo: due processi hanno la necessità di utilizzare
in modo esclusivo alcune risorse che servono a entrambi e
si trovano a competere per ottenerle;
● cooperativo: per svolgere uno specifico compito i processi
devono scambiarsi informazioni.
Programmazione concorrente
Sia per la cooperazione che per la competizione sono necessari
meccanismi di sincronizzazione e comunicazione:
● uso della memoria condivisa per far sì che alcuni dati di un
processo, se modificati, possano essere visti da un altro;
● scambio di messaggi per far sì che un processo possa
trasmettere informazioni a un altro.
Programmazione concorrente
Mutua esclusione
Quando è necessario che un solo processo alla volta abbia
accesso a un insieme di risorse comuni, si parla di mutua
esclusione tra processi concorrenti.
Dati due processi P1 e P2 e una risorsa R, si deve garantire
che:
1. in ogni istante, R sia libera oppure risulti assegnata a uno
solo tra P1 e P2 (mutua esclusione);
2. ciascuno dei due processi in esecuzione possa ottenere l’uso
della risorsa.
Programmazione concorrente
Per garantire queste condizioni è necessario che ogni processo
che utilizza una risorsa rispetti un protocollo articolato nelle
seguenti fasi:
1. richiesta della risorsa (necessaria per garantire la prima
condizione);
2. utilizzo della risorsa;
3. rilascio della risorsa (necessario per garantire la seconda
condizione).
Programmazione concorrente
Si definisce sezione critica
una parte di codice del
processo nella quale il
processo accede alla risorsa
per averne l’uso esclusivo.
Programmazione concorrente
Deadlock (stallo)
La realizzazione della mutua esclusione permette di evitare
problemi di interferenza tra processi, ma può causarne il
blocco permanente (deadlock). Questo avviene quando
ciascun processo attende che l’altro liberi una risorsa da lui
trattenuta.
Questa condizione è da evitare perché porta al blocco totale.
Nei sistemi informatici il deadlock è un problema che
coinvolge tutti i processi che utilizzano un certo insieme di
risorse. Se ne può uscire solo con metodi “distruttivi”,
mediante l’uccisione dei processi o riavviando la macchina.
Programmazione concorrente
Starvation (inedia)
Un altro caso che può verificarsi è quello in cui un processo
non può accedere a una risorsa perché questa risulta “sempre
occupata”.
Per esempio, se siete in coda dal salumiere e continuano ad
arrivare clienti disonesti, che vi passano davanti, non
riuscirete mai a farvi servire.
Si verificherà allora una condizione di starvation che, a
differenza del deadlock, non è una condizione definitiva ed è
possibile uscirne adottando un’opportuna politica di
assegnamento.
Programmazione concorrente
Realizzazione della mutua esclusione
Programmazione concorrente
Nell’acquisizione delle risorse si
devono effettuare due
operazioni, una per controllare
lo stato del semaforo e l’altra
per porre il semaforo nello
stato di occupato.
Programmazione concorrente
Per realizzare la mutua
esclusione nell’accesso della
risorsa si fa precedere la
lock() e seguire la unlock()
all’uso della risorsa, come
mostrato in figura.
Programmazione concorrente
Per rendere mutuamente esclusive
la wait e la signal si può
procedere nel modo illustrato in
figura.
Programmazione concorrente
Produttore-consumatore
Soluzione
• Sospendere il produttore se il buffer è pieno; sospendere il consumatore se il
buffer è vuoto
Produttore Consumatore
Programmazione concorrente
Produttore-consumatore
Situazioni da evitare:
• un consumatore legge un dato senza che un produttore ne
abbia depositato alcuno
• un produttore sovrascrive un dato prima che il consumatore
sia riuscito a leggerlo
• un dato viene letto dai consumatori più di una volta
Programmazione concorrente
Produttore-consumatore
Soluzione algoritmica
• due semafori
• dep (0 – blocca il consumatore)
• prel (1 – dà via libera al produttore)
Produttore Consumatore
Programmazione concorrente
Produttore-consumatore
Soluzione algoritmica
Programmazione concorrente
Produttore-consumatore
Soluzione algoritmica
Programmazione concorrente
Il problema dello stallo (deadlock)
Mutua esclusione
• Stallo
• due o più processi si ostacolano a vicenda impedendosi reciprocamente di portare a
termine la propria evoluzione
• I processi coinvolti nel deadlock ostacolano anche eventuali altri processi
• Le risorse a loro allocate non possono essere utilizzate da nessun altro processo
Programmazione concorrente
Lo stallo nei sistemi informatici
Situazione:
• due processi P1 e P2 che devono far uso sia di R1 che di
R2 per poter terminare il loro compito
• attesa circolare:
• il sistema operativo assegna R1 a P1 e R2 a P2
• P2 non potrà terminare giacché ha bisogno anche di R1
che è assegnata a P1
• P1 non potrà terminare giacché ha bisogno anche di R2
Grafo di Holt
che è assegnata a P2
• Situazione stallo
Programmazione concorrente
Perché si genera un deadlock
Condizioni di Coffman:
1. mutua esclusione
• le risorse vengono rilasciate solo a fine lavoro e una risorsa non
condivisibile deve essere utilizzata da un solo processo alla volta
2. impossibilità di prerilascio forzato
• Il sistema non può sottrarre forzatamente una risorsa al processo; una
risorsa può essere rilasciata volontariamente dal processo che la controlla
solo dopo che ha terminato di usarla
3. allocazione parziale e richieste bloccanti
• il processo non impegna, all’inizio del blocco critico, tutte le risorse di cui
avrà bisogno ma le richiederà (bloccandole) man mano che serviranno
(hold and wait)
4. attesa circolare
• Devono essere presenti almeno due processi, ciascuno dei quali in attesa di
una risorsa impegnata dall’altro.
Programmazione concorrente
Gestione dello stallo
Programmazione concorrente
Individuazione dello stallo
Grafi di Holt
• Resource Allocation Graphs (RAG)
• Associano al processo le risorse di cui
necessitano
Programmazione concorrente
Individuazione dello stallo
Grafi di Holt
Programmazione concorrente
Individuazione dello stallo
Presenza di un ciclo
presenza di un deadlock.
Programmazione concorrente
Individuazione dello stallo
Programmazione concorrente
Individuazione dello stallo
Programmazione concorrente
Individuazione dello stallo
Programmazione concorrente
Individuare e risolvere lo stallo
Programmazione concorrente
Individuare e risolvere lo stallo
Soluzioni
• terminazione dei processi
• metodo più semplice ma più drastico
• terminazione parziale (un processo per volta)
• non risolve? terminazione totale
• scegliere quale processo far ripartire
• preemption
• prerilascio di una risorsa da parte di uno dei processi in stallo
risorsa acquisita da altro processo che evolverà
• non idonea per tutte le risorse (es. stampanti)
• checkpoint/rollback
• salvataggio periodico su disco dello stato dei processi in certi istanti
(checkpoint)
• deadlock? ripristino di uno/più processi a stato precedente
(rollback)
Programmazione concorrente
Individuare e risolvere lo stallo
Programmazione concorrente
Evitare lo stallo (avoidance)
Programmazione concorrente
Algoritmo del banchiere
Programmazione concorrente
Algoritmo del banchiere
Soluzione
Clienti:
• possono chiedere un prestito una o più volte MA
• somma totale massima non superiore a quanto dichiarato in anticipo
Banchiere:
• cliente chiede prestito? banca è in stato sicuro? richiesta
accordata
• Banca in stato sicuro i soldi rimanenti in cassa, dopo aver soddisfatto
la richiesta corrente, permettono di soddisfare almeno una successiva
richiesta massima da parte di un cliente che ancora non ne ha fatte
Programmazione concorrente
Algoritmo del banchiere - Esempi
Programmazione concorrente
Algoritmo del banchiere - Esempi
Programmazione concorrente
Algoritmo del banchiere - Esempi
Traduzione informatica:
• ogni processo deve dichiarare il massimo numero di risorse che gli
sono necessarie
• a ogni richiesta di una nuova risorsa l’algoritmo deve verificare cosa
succede nel caso in cui venga soddisfatta questa richiesta
• la richiesta porta il sistema a uno stato sicuro o insicuro?
• si calcola la quantità di risorse rimanenti nel caso che questo
processo venga servito e si valuta se queste risorse possono soddisfare
la massima richiesta di almeno un processo che ancora deve essere
servito
• se sì l’allocazione viene accordata, altrimenti viene negata
Programmazione concorrente
Prevenire lo stallo
• Evitare il deadlock
• Eliminare una delle quattro condizioni che lo causano
• risorse seriali
• evitare la mutua esclusione permettendo la condivisione di
risorse
(Es. spool per gestire le code di stampa)
• hold & wait
• Allocazione totale
• escludere che un processo mantenga una risorsa anche
quando è in attesa di un’altra risorsa
• imporre che il processo richieda tutte le risorse all’inizio
• non sempre realizzabile
• Può provocare l’arresto di altri processi che
potrebbero evolvere (starvation)
Programmazione concorrente
Prevenire lo stallo
• Evitare il deadlock
• Preemption
• Forzare un processo a rilasciare le risorse in uso quando ne
richiede un’altra in quel momento indisponibile
• Il processo ripartirà quando potranno essergli assegnate tutte
le risorse precedenti e l’ultima richiesta
• Non sempre realizzabile (es. stampa in corso)
• attesa circolare
• Allocazione gerarchica
• Assegnazione di valori di priorità alle classi di risorse
• Ogni processo in ogni istante può allocare solo risorse di
priorità superiore a quelle che già possiede
• Per ottenere risorse con priorità inferiore deve rilasciare le
altre
• Assegnazione risorse ai processi secondo un ordine
prestabilito (a carico dell’amministratore del sistema)
• Introduce gravi rallentamenti
Programmazione concorrente
Ignorare il problema
Programmazione concorrente
Il problema dei cinque filosofi
Programmazione concorrente
Il problema dei cinque filosofi
Programmazione concorrente
Il problema dei cinque filosofi
PRO CONTRO
• meccanismo molto potente per la • utilizzo spesso rischioso e
sincronizzazione dei processi difficoltoso
• primitive di “basso livello”
• il programmatore può causare
situazioni di deadlock
• esecuzioni erronee di difficile
verifica (race condition) per
errato/improprio uso delle
primitive
Programmazione concorrente
Soluzione
Monitor
• proposto da Hoare nel 1974 e da Brinch-Hansen nel 1975
• controllo esplicito delle regioni critiche mediante costrutti
linguistici “a più alto livello“
• è il compilatore che introduce il codice necessario al
controllo degli accessi
Programmazione concorrente
Monitor: definizione e generalità
Programmazione concorrente
Uso dei monitor
Utilizzati per
• per il controllo degli accessi a una risorsa condivisa tra processi
concorrenti
• in base a politiche di gestione
• le variabili locali definiscono lo stato della risorsa associata al
monitor
• i processi possono aggiornare lo stato della risorsa mediante le
procedure entry
Usati come
• istanza di monitor
• oggetto di tipo monitor
Programmazione concorrente
Sincronizzazione mediante i monitor
• Sulle variabili di tipo condition si accede solamente mediante due procedure: wait() e signal()
• hanno come parametro la variabile sulla quale devono operare
• miaCondition è la variabile condition che deve essere testata: il processo che la esegue si sospende,
viene posto nella coda associata e libera il monitor
• miaCondition è la variabile condition da testare per liberare un processo in attesa: se la coda a esso
associata contiene almeno un processo, questo viene risvegliato e riprenderà l’esecuzione dentro il monitor,
a partire dall’istruzione seguente dalla wait() che lo aveva sospeso
• se non sono presenti processi in coda l’operazione non ha nessun effetto
• deve essere l’ultima istruzione eseguita dal processo all’interno del monitor; se viene risvegliato un
processo in attesa sullo stesso monitor questo lo troverà libero
Programmazione concorrente
dati condivisi che servono
alle entry per regolare
l’accesso alla risorsa:
- Stato della risorsa
- Condizione per gestione
coda attesa
Programmazione concorrente
Segmento di codice che “utilizza la risorsa”
Programmazione concorrente
Riepilogando
Programmazione concorrente