Sei sulla pagina 1di 42

Thread

Concetti essenziali

1
Programma
lunit di esecuzione allinterno del
S.O.
Solitamente, esecuzione sequenziale
(istruzioni vengono eseguite in
sequenza, secondo lordine specificato
nel testo del programma).
Un processo un programma in
esecuzione.
S.O. multiprogramma permettono
l'esecuzione concorrente di pi
processi.

2
Processo
un programma in esecuzione,
ogni processo ha un proprio spazio
di indirizzamento, un proprio PCB e
lelenco delle risorse possedute.
Lesecuzione delle operazioni di
context switch richiede tempo
utile di CPU che, quindi, viene cos
sprecato per effettuare queste
operazioni non produttive, esse
chiamate overhead o tempo di
gestione del multitasking.
3
PCB e context switch
Il PCB viene assegnato ad un processo Labbandono del processore da parte di
quando viene posto nello stato new e un processo provoca il cosiddetto
viene de-assegnato quando esce dallo cambiamento di contesto (context switch)
stato terminated e ne viene persa traccia. nel senso che tutti i dati presenti nei
I PCB contengono tutte le informazioni registri del processore vengono salvati nel
del programma: prossima istruzione da PCB e ne vengono messi altri di un altro
eseguire, puntatore allo stack, puntatore processo.
allheap, tempo di uso della cpu Quando ritocca al processo precedente il
I PCB contengono un identificatore contenuto dei registri del processore
univoco per ogni processo, e tra un viene ripristinato con le informazioni
processo e laltro il PCB sempre diverso. prelevate dal PCB di questultimo.

4
Stati di un Processo
Init: acquisizione delle risorse
Ready: processo pronto ad
essere eseguito.
Running: processo in
esecuzione.
Waiting: processo sospeso in
attesa di un evento esterno.
Terminated: processo concluso.

5
Processi leggeri o Thread - 1
Un Thread un singolo flusso di esecuzione di
un processo.
Un processo pu avere pi Thread, che
condividono alcune risorse.
Ad ogni thread associato in modo esclusivo
il suo stato della computazione, fatto dal
valore del program counter e degli altri
registri della CPU e da uno stack.
I thread di uno stesso processo vedono le
stesse variabili: se uno dei thread modifica
una variabile, la modifica vista anche dagli
altri thread.

6
Processi leggeri o Thread - 2
La nomenclatura processi leggeri
deriva dal fatto che alla fine un
Thread simile ad un processo: ha
un proprio identificativo univoco,
un proprio TCP (thread control
block), subisce azioni di context
switch, naturalmente pi leggero
di quello di un processo.
Ogni thread ha un proprio
identificativo ed un proprio stack,
mentre condivide lheap.
7
Stati di un Thread
Idle: prima di essere avviato;
Dead: terminate le sue
istruzioni;
Blocked: in attesa di
completare lI/O;
Sleeping: sospeso un periodo;
Waiting: in attesa di un evento;
Running: in esecuzione;
Ready: pronto per lesecuzione
ma in attesa della CPU.
8
Thread e Processi: pregi e difetti

9
Thread user level e kernel level
Implementati attraverso librerie a SO associa ad ogni thread a livello
user-level. user un kernel thread
Creazione, scheduling, Ogni kernel thread viene
sincronizzazione thread tramite schedulato indipendentemente
librerie: Tutte le operazioni sui thread sono
lOS ignora la presenza dei thread. eseguite dal SO operations
lOS vede solo i processi con un (creazione, scheduling,
singolo thread. sincronizzazione)
Non pu sfruttare sistemi Operazioni sui thread pi costose
multiprocessore in termini di tempo

10
Multithreading
Ed i relativi problemi

11
Programma multithreading 1
un programma formato da pi
thread che collaborano per poter
ottenere uno scopo comune.
Lo scopo comune dei thread per
esempio cambiare le ruote
allauto.
Infatti inimmaginabile che in
una gara di formula 1 sia un
singolo meccanico (thread) a
http://gph.is/2pdmez8 cambiare ruote.

12
Programma multithreading 2
Possiamo vedere un programma
multithreading come un flusso
di esecuzione indipendente dagli
altri, ma connesso agli altri in un
unico programma.

13
Programma multithreading 3
Lutilizzo dei thread serve solo e
solamente per bilanciare il
programma.
Bisogna evitare di far lavorare
troppo o troppo poco un thread.
Il bilanciamento del carico di
lavoro necessario per
ottimizzare il programma.

14
Programma multithreading 4
Le risorse condivise sono quelle a
cui tutti i thread possono
accedere in parallelo.
Se si legge e/o modifica la stessa
risorsa condivisa nello stesso
istante potremmo realizzare
un'azione che provoca dei risultati
non deterministici (inaspettati).
Si devono maneggiare con
cautela.

15
Programma multithreading 5
Se due processi (o thread) che operano in parallelo sono
completamente indipendenti tra loro non si presenta nessun
particolare problema. Ma in molti casi i processi concorrenti possono
interagire tra loro con due modalit: COMPETIZIONE E
COOPERAZIONE.
COMPETIZIONE: I processi competono tra loro per laccesso e lutilizzo di una
risorsa che non possono utilizzare entrambi contemporaneamente.
COOPERAZIONE: I processi devono cooperare per realizzare un determinato
compito. Pu essere necessaria la condivisione di risorse e la comunicazione.

16
Risorse condivise 1
Lutilizzo delle risorse condivise da parte dei
thread.
Quando due o pi thread vengono eseguiti in
maniera concorrenziale, in generale
impossibile prevedere l'ordine in cui le loro
istruzioni verranno eseguite.
I risultati dipendono esclusivamente
dallordine di esecuzione delle istruzioni.
I risultati non deterministici sono da evitare in
tutti i modi, in quanto il programmatore NON
SA cosa succede in tutti i singoli casi.
Oltre a provocare risultati non deterministici
possono portare ad altri errori e anche gravi.

17
Risorse condivise 2
Bisogna limitare luso delle risorse
condivise ad un singolo thread per
volte.
Se una risorsa condivisa pu provocare
danni se usata da due thread insieme
bisogna realizzare un sistema per
evitare laccesso parallelo e serializzare,
essa una sezione critica.
La sezione critica un processo di
modifica di un insieme di variabili
condivise.

18
Risorse condivise 3

19
Risorse condivise 4
Letture e scritture nello stesso istante
provocano a risultati non determinabili a
priori.
Questo ci impone di dover realizzare delle
politiche di prevenzione dei risultati non
deterministici.
Queste politiche rendono il la risorsa
safe.
Se c uno context switch tra due
istruzioni critiche la risorsa condivisa
potrebbe essere in uno stato di
inconsistenza.

http://gph.is/2pduIGC

20
Operazioni atomiche
Un'istruzione atomica una istruzione indivisibile a livello di esecuzione:
non ci pu essere un context switch allinterno di una istruzione atomica.
Ovvero se nessunaltra istruzione pu cominciare prima che sia finita
(ovvero non pu esserci interleaving).
In caso di modifica di un'area critica in operazioni separate da context
switch si rischia una inconsistenza della variabile.

21
Serializzare il parallelo 1
Le politiche per rendere una
risorsa sicura si basano sul fatto
di serializzare laccesso alla
risorsa.
Serializzando laccesso si
creeranno dei tempi morti. In
questi tempi morti bene
mettere il processo in stato di
attesa e non sprecarlo con busy
wait.

22
Serializzare il parallelo 2
Per serializzare laccesso ad una
risorsa si pu usare un sistema
simile a quello che avviene nei
bagni: realizzare una serratura
che ti dice se puoi entrare o
meno allinterno della risorsa.
Se non entri rimani in attesa in
una coda.
Questo tipo di sicurezza viene
chiamato mutua esclusione
http://gph.is/2q7q55W (mutex).
23
Mutua esclusione
La regola di mutua esclusione stabilisce che in ogni istante
una risorsa o libera oppure assegnata a uno e un solo
processo: in particolare per avere la mutua esclusione
devono essere soddisfatte le seguenti quattro condizioni:
nessuna coppia di processi pu trovarsi
simultaneamente nella sezione critica;
laccesso alla regione critica non deve essere regolato
da alcuna assunzione temporanea o dal numero di
CPU;
nessun processo che sta eseguendo codice al di fuori
della regione critica pu bloccare un processo
interessato a entrarvi;
nessun processo deve attendere indefinitamente
per poter accedere alla regione critica.
In una sezione critica con una mutua esclusione essa pu
eseguita una sola volta a ogni istante.

24
Serializzare il parallelo 3
Ma se esistono due bagni uno
accanto allaltro non ha senso
realizzare due code distinte, ma
bens una univoca.
Questaltra tecnica invece un
controllo del flusso basata su
semafori contatori.
Come si pu intuire la mutua
esclusione un semaforo che fa
http://gph.is/2qM6AMm passare una persona alla volta.
25
Deadlock 1
Supponiamo che il Thread 1 stia
bloccando loggetto 1 e che voglia
loggetto 2, bloccato dal Thread 2.
Supponiamo inoltre che il Thread
2 stia bloccando loggetto 2 e che
voglia loggetto 1, bloccato dal
Thread 1.
Questa specifica situazione di
blocco a vicenda viene chiamato
deadlock.

26
Deadlock 2

27
Starvation
Accade quando un Thread di
bassa priorit non viene mai
mandato in esecuzione in
quanto ci sono altri thread con
una maggiore priorit.
Come quando siete in coda a
uno sportello e continuano ad
arrivare furbi che passano
davanti, impedendomi di
avanzare verso limpiegato.

28
Thread safety
Un programma concorrente deve godere di alcune
propriet che devono essere valide per ogni
possibile caso di esecuzione del programma
stesso:
Sicurezza delle risorse condivise: i thread non
devono interferire tra di loro su una modifica
ad una risorsa condivisa, ci devono essere
meccanismi di sincronizzazione.
Liveness: bisogna garantire che il processo
avanzi sempre, e quindi evitando situazioni di
deadlock.
Fiarness: tutte le richieste devono essere
soddisfatte, evitando code a priorit, e quindi
evitando la starvation.

29
Come realizziamo il Thread safety?
Dobbiamo serializzare le richieste E.W. Dijkstranel 1968 ha proposto due
delluso di una risorsa condivisa e primitive che permettono la soluzione
lutilizzo della stessa deve avvenire per di qualsiasi problema di interazione fra
un tempo finito e breve. processi, che sono:
Cos evitiamo tutti i possibili problemi la primitiva P(S), che riceve in
derivanti. ingresso un numero intero S non
Per questo sono state ideate delle negativo (semaforo), che viene
primitive: esse sono delle linee guida utilizzata per accedere alla risorsa.
che poi vengono implementate dai vari la primitiva V(S), che riceve in
linguaggi di programmazione che
dicono come gestire situazione. ingresso un numero intero S non
negativo (semaforo), che viene
utilizzata per rilasciare la risorsa.

30
Semaforo di Dijkstra 1
Un semaforo formato da una
variabile intera contatore.
Se il semaforo vale zero non si pu
accedere alla risorsa e si deve
attendere
Se il semaforo vare pi di zero indica
libero ed il valore dice quanti processi
possono ancora accedere alla risorsa.
Se si usa un mutex, cio un semaforo
binario il valore massimo di thread
che accedono alla risorsa 1

31
Semaforo di Dijkstra 2
1. Il macchinista di A controlla lo stato del
semaforo (esegue una P(S)): lo trova spento,
quindi lo accende (S = 0) e inizia a transitare sul
ponte;
2. anche il treno B sopraggiunge al ponte ma
trovando il semaforo acceso esegue anchesso
una P(S), si ferma e rimane in attesa.
3. A continua la sua corsa attraversando il ponte;
4. una volta raggiunta laltra sponda, spegne il
semaforo (S=1);
5. B ora vede il semaforo spento e lo accende
(S=0) e inizia pure lui ad attraversare il ponte.

32
Primitiva P(S)
Serve per acquisire la risorsa, fa
un controllo ciclico se la risorsa
disponibile e quando
disponibile decrementa il valore
del semaforo.
Nomi comuni della
implementazione della suddetta
primitiva: acquire, lock, enter,
wait

33
Primitiva V(S)
Incrementa il valore del semaforo ed esce
dallarea critica.
Essendo la variabile del semaforo un intero
rende che le primitive P(S) e V(S)
permettono di regolare l'accesso non solo a
due processi ma anche laccesso multiplo di
numerosi processi.
Nomi comuni della implementazione della
suddetta primitiva: signal, release, unlock,
exit
P(S) e V(S) sono primitive indivisibili

34
Utilizzo delle primitive P(S) e V(S)
Prima di accedere alla zona critica del
programma viene lanciata la primitiva
P(S) che blocca la risorsa.
Viene eseguito il codice a rischio.
Viene eseguita la primitiva V(S) che
rilascia la risorsa.
Attenzione: sempre necessario usare
adeguati sistemi Try-Catch-Finally
gestire le eccezioni e lanciare sempre
ed in qualunque caso anche la V(S)
dopo aver eseguito la P(S).

35
Semafori a conteggio e buffer
Una delle limitazioni dei vettori in
molti linguaggi di programmazione
la dimensione fissa degli array.
Per evitare questo possiamo usare
dei semafori per ritardare
laggiunta di un elemento in attesa
che il buffer si svuoti.
Si realizza con il semaforo di
Dijkstra a conteggio (quello non
binario)
http://gph.is/2pdHJ2E

36
I semafori sono difficili
I semafori sono un meccanismo molto
potente per realizzare la sincronizzazione dei
processi ma il loro utilizzo spesso molto
rischioso e talvolta difficoltoso in quanto sono
primitive ancora di basso livello e il
programmatore pu causare situazioni di
blocco infi nito (deadlock) o anche esecuzioni
erronee di diffi cile verifica (race condition)
per un errato o improprio posizionamento
delle primitive di P(S) e V(S).
I semafori lasciano al programmatore troppa
responsabilit nellutilizzo di queste strutture
di controllo cos delicate.

37
I Monitor - 1
Per ovviare a problemi di questa natura nei
linguaggi evoluti di alto livello , si sono
introdotti costrutti linguistici a pi alto
livello per realizzare il
controllo esplicito delle regioni critiche,
dove il compilatore che introduce il codice
necessario al controllo degli accessi: questo
meccanismo fu chiamato monitor, proposto
da Hoare nel 1974.
Il monitor definisce la regione critica e
realizza la mutua esclusione nellaccesso
allarea critica: un solo processo alla volta
pu essere attivo entro il monitor.

38
I Monitor - 2
Laccesso, e quindi Costrutto sintattico che associa
lassegnazione della risorsa, un insieme di
avviene secondo due livelli di procedure/funzioni (public o
controllo: entry) a una
1)Quello che garantisce la mutua struttura dati comune a pi
esclusione processi, tale che:
2)Quello che controlla lordine Le operazioni entry sono le
con il quale i processi hanno uniche operazioni permesse su
accesso alla risorsa quella struttura e sono
mutualmente esclusive.
39
Monitor e semafori
possibile realizzare un
monitor basato su un semaforo
come possibile realizzare un
semaforo basato sul monitor.
Questa sorta di corrispondenza
rende i due metodi equivalenti
nella programmazione
concorrente.

40
Sincronizzazione tra thread - 1
Esistono delle primitive per
poter inviare dei segnali
wait() : addormenta il thread in
attesa della risorsa.
notify() o signal() : risveglia un
thread in attesa della risorsa.
notifyAll() o signalAll() :
risveglia tutti i thread in attesa
della risorsa.

41
Sincronizzazione tra thread - 2

I Thread bloccati dal wait possono essere risvegliati tutti con il


notifyAll/signalAll oppure uno, scelto secondo una politica
FIFIO/LIFO/P.QUEUE.

42

Potrebbero piacerti anche