1. Svantaggi legati all'uso di processi
• La gestione tradizionale dei processi può
diventare molto onerosa dal punto di vista
computazionale
– Creazione: allocazione dello spazio di
indirizzamento, e successiva popolazione
– Context switch: salvataggio e ripristino degli
spazi di indirizzamento (codice, dati, stack) di
due processi
• Con una applicazione con molti processi
(server), il SO rischia di passare la maggior
parte del tempo a svolgere operazioni interne
di gestione, piuttosto che ad eseguire codice
applicativo
1
2. Svantaggi legati all'uso di processi
• La nozione classica di processo ingloba due
concetti ben distinti, gestiti dal SO:
– Gestione delle risorse: ciascun processo ha
assegnati un proprio spazio di indirizzamento
(solitamente, indipendente) ed alcune risorse
– Esecuzione traccia: ciascun processo esegue
porzioni di codice sequenzialmente e
concorrentemente con altri processi
• La gestione dell'esecuzione di una traccia non
comporta particolari aggravi computazionali,
essendo direttamente gestita dal processore
• La lentezza della gestione risiede nella
complessità della gestione delle risorse del
processo 2
3. Separazione risorse-esecuzione
• Nei SO moderni, i due concetti ora visti
possono essere disaccoppiati
– L'unità base di esecuzione di una traccia prende
il nome di thread
– L'unità base proprietaria delle risorse prende il
nome di processo
• Ciascun processo può essere visto come:
– un contenitore di risorse
– un contenitore di codice
– Uno strumento per far partire tracce sequenziali
(“fili” di codice, thread) di esecuzione del
codice
3
4. Thread
• Un thread è l'insieme dei dati utilizzati per
eseguire, in maniera concorrente, più tracce
relative al codice di un processo
• Tutti i thread generati da un processo ne
condividono il codice e le risorse
• In tal modo, le operazioni di gestione non
toccano praticamente più lo spazio di
indirizzamento!
– L'aggravio di gestione si riduce sensibilmente
• Un SO in grado di gestire i thread è detto
multithreaded
• Tutti i SO moderni supportano il multithreading
4
5. Ambiente a processi (single threaded)
• Ciascun processo processo
file
contiene tutte le
PCB
informazioni per
dati
poterlo eseguire
• Ambiente single stack
IP
threaded: ciascun
processo può
codice
eseguire al più una
traccia
traccia in
• Informazioni: esecuzione
– Spazio indirizzi
– Risorse prenotate
– Registri interni
5
6. Ambiente multithreaded
• Ciascun processo processo
file
contiene tutte le
PCB
informazioni per
dati
poterlo eseguire
• Ambiente codice
IP
multithreaded: ogni
thread esegue
TCB TCB TCB
tracce di codice
• TCB: Thread Control
IP stack IP stack IP stack
Block (simile a PCB)
– Registri, Stack traccia in traccia in traccia in
esecuzione esecuzione esecuzione
– Variabili “locali”
– Stato esecuzione
6
8. Benefici del multithreading
• Reattività
– Il blocco di un thread non inficia gli altri
– Maggiore fluidità di esecuzione
• Condivisione risorse
– I thread condividono la memoria e le risorse del
processo che li ha generati
• Economia
– Alloco e distruggo risorse di processo una volta
• Architetture SMP
– I thread eseguono in parallelo sui diversi
processori
– Il singolo processo non li può sfruttare
8
9. Problemi del multithreading
• Modello di programmazione complesso
– La condivisione delle risorse e della memoria
implica spesso la gestione della concorrenza
degli accessi a queste ultime
– Ulteriori passi di programmazione, spesso
complessi
• Debugging complesso
– E' molto difficile riprodurre bug in presenza di
accessi concorrenti alle risorse
– E' spesso difficile individuare le cause del bug
9
10. Applicazioni del multithreading
• Quali applicazioni si lasciano implementare
tramite i thread? Tutte quelle applicazioni:
– che possono essere spezzate in più parti da
eseguire concorrentemente/parallelamente
– in cui alcune parti si bloccano spesso per fare I/
O, mentre altre no
– che devono gestire eventi asincroni (bottone
STOP del browser)
10
11. Supporto del SO ai thread
• Il SO deve fornire un supporto per la gestione
dei thread
– Supporto allo user level, tramite librerie di
funzioni (API) per gestire n thread in esecuzione
– Supporto al kernel level, tramite una astrazione
di traccia di esecuzione
• Le diverse implementazioni di supporto ai
thread svariano da un estremo all'altro
– Implementazioni puramente a livello applicativo
– Implementazioni puramente a livello kernel
– Implementazioni “miste”
• Adozione di molteplici modelli di
multithreading
11
12. Modello Many-to-One (N:1)
• A più supporti user level corrisponde un solo
supporto kernel level
– Il kernel vede una sola traccia di esecuzione,
ossia solo un processo che esegue
– Il processo usa delle funzionalità applicative per
simulare uno scheduler di mini-processi
– I mini-processi non sono noti al kernel del SO
– Ciascun mini-processo è, in realtà, una
astrazione per eseguire una traccia di una
funzione del processo
• Implementazioni: Green threads (Solaris), GNU
Portable Threads, Java threads, Ruby threads
12
13. Modello Many-to-One (N:1)
Create, stop, schedule,
Processo
resume, destroy
Main
Thread
library User
space
Thread Thread Thread
PCB
Kernel
space
13
14. Modello Many-to-One (N:1)
• Vantaggi
– Gestione efficientissima dei thread (non viene
coinvolto lo scheduler del kernel)
– Non richiede un kernel multithreaded per poter
essere implementato
• Svantaggi
– Se un thread effettua una chiamata bloccante, il
processo si blocca, e con esso tutti i thread
– I thread sono legati allo stesso processo, e non
possono eseguire su processori fisici distinti
14
15. Modello One-to-One (1:1)
• Ad un supporto user level corrisponde un
supporto kernel level
– Il kernel vede una traccia di esecuzione distinta
per thread; ho l'analogo di un PCB per ciascun
thread in esecuzione
– Il processo usa una system call simile a fork()
per invocare il meccanismo di creazione
– I thread vengono schedulati dallo scheduler del
kernel, come tutti gli altri processi
• Implementazioni: GNU/Linux (LinuxThreads,
NPTL), Windows 95/98/2000/XP/NT
15
16. Modello One-to-One (1:1)
Processo Thread Thread
Thread Thread
Main
function function User
space
Create,
f
destroy
Kernel
PCB TCB TCB
space
16
17. Modello One-to-One (1:1)
• Vantaggi
– Se un thread effettua una chiamata bloccante,
non blocca gli altri thread
– I thread sono rappresentati da altrettanti TCB, e
possono essere eseguiti su processori fisici
distinti
• Svantaggi
– Gestione meno efficiente dei thread (usa lo
scheduler del kernel)
– Richiede un kernel multithreaded per poter
essere implementato
17
18. Modello Many-to-Many (N:M)
• Ad N supporti user level corrispondono M
supporti kernel level (N>M)
– Unione del modelli 1:1 ed N:1; intende prendere
il meglio dei due modelli
– Il processo usa una system call simile a fork()
per creare M thread kernel level
– Ciascuno di questi M kernel level thread crea N/
M thread user level
• Implementazioni: IRIX, HP-UX, Tru64 UNIX,
Solaris (fino a V.9)
18
19. Modello Many-to-Many (N:M)
ProcessoCreate, stop, sched, ProcessoCreate, stop, sched,
resume, destroy resume, destroy
Main Main
Thread Thread
library library
User
space
Thread Thread Thread Thread Thread Thread
Kernel
PCB TCB
space
Create,
destroy
19
20. Quando si applicano i modelli?
• Modello Many-to-One
– Buono per applicazioni di tipo parallelo con
pochissimo I/O
– Lo scheduler del kernel non le rallenta
– Thread non schedulabili su più processori
• Modello One-to-One
– Ideale per applicazioni di tipo parallelo o
distribuito con tanto I/O (server)
– Mantiene elevato il grado di concorrenza
– Ha soppiantato tutti gli altri modelli
• Modello Many-to-Many
– Concepito per applicazioni suddivise in una
parte I/O (1:1) ed in una parte di calcolo (M:1) 20
21. Multithreading: creazione/immagine
• In un programma multithreaded la semantica
delle operazioni fork() ed exec() cambia
• Se un thread invoca la chiamata fork():
– può duplicare se stesso
– può duplicare l'intero gruppo di thread
• Se un thread invoca la chiamata exec():
– Sovrascrive l'immagine di tutti i thread e del
processo invocante
• Solitamente, si evita l'uso della exec() in
ambiente multithreaded
– Si associano i thread a funzioni che devono
essere eseguite
21
22. Multithreading: cancellazione
• La cancellazione è l'operazione di terminazione
prematura di un thread
• Il thread selezionato per una cancellazione è
chiamato thread bersaglio (target thread)
• La cancellazione del target bersaglio può
avvenire in due modalità distinte:
– cancellazione asincrona: un altro thread uccide
direttamente il thread bersaglio
– cancellazione differita: il thread bersaglio
controlla periodicamente (cancellation point) se
deve terminare, in modo da uscire in maniera
pulita
22
23. Multithreading: gestione segnali
• In ambiente single threaded, il segnale viene
inviato ad un processo
• In ambiente multithreaded, a quale thread va
inviato il segnale?
– al thread cui il segnale si riferisce
– a ciascun thread (CTRL-C)
– a specifici thread
♦ il primo thread che non blocca il segnale
♦ Identificato dal TID
– ad un thread speciale, di controllo (Solaris 2)
23
24. Multithreading: thread pool
• All'aumentare del numero di flussi concorrenti,
le risorse del sistema possono esaurire
rapidamente
• Per impedire l'esaurimento delle risorse, un
software multithreaded pre-crea un insieme di
thread (thread pool)
– Quando viene lanciato un thread, lo si preleva
dal gruppo
– Quando un thread termina, lo si restituisce al
gruppo
– Le operazioni di creazione/distruzione sono
molto più veloci
– Si limita il numero di thread in esecuzione
24
25. Multithreading: Thread Specific Data
• In particolari circostanze, ciascun thread può
necessitare di una copia privata di alcuni dati,
detti dati specifici (thread locale)
– Variabili “globali” per thread
– Variabili “static” per thread
• La maggior parte delle librerie pthread
forniscono il supporto per i thread locale
25
26. Modelli di programmazione
• L'uso dei thread permette l'implementazione
efficiente di alcuni modelli di programmazione
• Modello Pipeline:
– I thread eseguono “a catena”, uno dopo l'altro
• Modello Master-Slave:
– Il thread master coordina l'esecuzione dei
thread slave (che effettuano il lavoro vero e
proprio)
• Modello Worker:
– Tutti i thread lavorano
26
28. Librerie di threading
• Ciascuna implementazione del supporto ai
thread fornisce una libreria di funzioni (thread
library) per la gestione dei thread
– La libreria può fare uso nullo, parziale o
completo delle funzionalità offerte dal kernel
• Implementazioni:
– Pthreads: standard POSIX, kernel level
– Win32: kernel level
– Java: user level
28
29. Libreria Pthreads
• Standard ANSI/IEEE POSIX 1003.1
– Gestione thread: creazione, distruzione,
sincronizzazione
– Gestione concorrenza: meccanismo dei mutex
– Comunicazione concorrente: meccanismo per
creare, distruggere e segnalare thread sulla
base dei valori di specifiche variabili condizione
(condition variables)
• Più di 60 funzioni per gestire thread come tipi
di dato opachi (pthread_t)
• Concepita per i linguaggi C, C++
• Compilazione: gcc -pthread
– include <pthread.h>
29
30. Creazione thread
• Signature: int pthread_create(
pthread_t *thread, pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
– Descrizione: crea un nuovo thread, eseguente
la funzione start_routine con argomento arg
– Ingresso:
♦ Un puntatore alla struttura thread identificante il
thread da eseguire
♦ Un puntatore alla struttura “attributi” che
imposta le caratteristiche del thread (NULL)
♦ Un puntatore alla funzione start_routine
♦ Un puntatore all'argomento arg
30
31. Creazione thread
• Signature: int pthread_create(
pthread_t *thread, pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
– Descrizione: crea un nuovo thread, eseguente
la funzione start_routine con argomento arg
– Ritorno:
♦ 0 -> tutto ok
– Il TID del thread appena creato è salvato
all'interno della struttura dati thread
♦ !=0 -> errore
– tipicamente, le risorse del sistema sono
insufficienti per la creazione di un thread
31
32. Creazione thread
• Un thread, a sua volta, può creare altri thread con
la pthread_create()
• Non esiste gerarchia o dipendenza fra I vari
thread
32
33. Terminazione thread
• Le cause di terminazione di un thread sono
molteplici
– Il thread ritorna dalla funzione
– Il thread invoca una chiamata di funzione
pthread_exit()
– Il thread è cancellato da un altro thread tramite
la funzione pthread_cancel()
– Il processo invocante carica un'altra immagine
con la funzione exec()
– Il processo invocante esce tramite la funziona
exit()
33
34. Terminazione thread
• Signature: void pthread_exit(void *retval);
– Descrizione: termina l'esecuzione del thread
invocante
– Ingresso:
♦ un puntatore ad una variabile in cui sarà
scritto il codice di uscita del thread (potrà
essere consultato tramite la pthread_join())
– Ritorno: nessuno
34
35. Attributi dei thread
• Ad un thread è associata una struttura dati
identificante le sue proprietà (attributi):
pthread_attr_t
• Tale struttura contiene una maschera di bit,
che rappresenta le proprietà attivate
• Alcune proprietà:
– Thread “joinabile”
– Algoritmo di scheduling utilizzato
– Scope delle variabili
35
36. Attributi dei thread
• Signature: int pthread_attr_init(pthread_attr_t
*attr);
– Descrizione: inizializza una struttura
pthread_attr_t
– Ingresso:
♦ un puntatore ad una struttura pthread_attr_t
– Ritorno:
♦ Sempre 0
36
37. Attributi dei thread
• Signature: int pthread_attr_destroy
(pthread_attr_t *attr);
– Descrizione: resetta una struttura pthread_attr_t
e rilascia le risorse allocate
– Ingresso:
♦ un puntatore ad una struttura pthread_attr_t
– Ritorno:
♦ Sempre 0
37
38. Attributi dei thread
• Signature: int pthread_set_detachstate
(pthread_attr_t *attr, int detachstate);
– Descrizione: imposta il flag “detached” del
thread con proprietà attr al valore detachstate
– Ingresso:
♦ Un puntatore ad una struttura pthread_attr_t
♦ Lo stato desiderato
(PTHREAD_CREATE_JOINABLE)
– Ritorno:
♦ 0: -> tutto OK
♦ !=0: un errore
38
39. Attributi dei thread
• Signature: int pthread_set_detachstate
(pthread_attr_t *attr, int detachstate);
– Descrizione: imposta il flag “detached” del
thread con proprietà attr al valore detachstate
– Ingresso:
♦ Un puntatore ad una struttura pthread_attr_t
♦ Lo stato desiderato
(PTHREAD_CREATE_JOINABLE)
– Ritorno:
♦ 0: -> tutto OK
♦ !=0: un errore
39
40. Sincronizzazione thread
• La sincronizzazione fra thread creante e thread
avviene in maniera simile ai processi
• Si utilizza la funzione pthread_join() (analogo
della waitpid())
• Il thread invocante (o il processo) si blocca
fino a quando un thread specificato da
threadid termina
• Il thread invocante (o il processo) può leggere
il codice di uscita
• A differenza dei processi, bisogna specificare
esplicitamente che un thread sia “joinabile”
40
41. Sincronizzazione thread
• Come si specifica la proprietà “joinable” sui
thread?
• Step 1: si dichiara una variabile “attributi” di
tipo pthread_attr_t
• Step 2: si inizializza la variabile con la funzione
pthread_attr_init()
• Step 3: si imposta l'attributo “detached” con la
funzione pthread_attr_setdetachstate()
• Step 4: in un punto successivo, si rilasciano le
risorse allocate con la funzione
pthread_attr_destroy()
41
43. Sincronizzazione thread
• Signature: int pthread_join (pthread_t th, void
**thread_return);
– Descrizione:
♦ sospende l'esecuzione del thread invocante
fino all'uscita del thread identificato da th
♦ Se thread_return != NULL, scrive il codice di
uscita nella cella puntata da thread_return
– Ingresso:
♦ un puntatore ad una struttura pthread_attr_t
– Ritorno:
♦ 0: -> tutto OK
♦ !=0: un errore
43
44. Concorrenza thread
• Per gestire l'accesso concorrente a variabili
condivise, si utilizza il costrutto dei semafori
– Variabili mutex (MUTual Exclusion): interi posti
a 0 (risorsa libera) o 1 (risorsa occupata)
pthread_mutex_t
– Ciascun mutex agisce come un lucchetto (lock)
sugli altri thread che vogliono accedere alla
risorsa
– Due stati:
♦ LOCKED: risorsa prenotata da un thread
♦ UNLOCKED: risorsa libera
– Impedisce le cosiddette corse critiche (accessi
simultanei a variabili condivise, con
indeterminatezza del risultato finale) 44
45. Concorrenza thread
• Scenario tipico di utilizzo dei mutex
– Creazione ed inizializzazione di una variabile di
tipo mutex
– Più thread provano a prenotare la risorsa,
cercando di ottenere il lock sul mutex
– Un solo thread ci riesce (quello che arriva per
primo) e prenota la risorsa per se
– Il thread modifica la risorsa in questione
– Il thread rilascia la risorsa
– Un altro thread acquisisce il lock sul mutex
– Il processo si ripete
– Il mutex viene distrutto
45
46. Concorrenza thread
• Dichiarazione mutex: può avvenire in due modi
distinti
– Dichiarazione statica:
pthread_mutex_t mymutex =
PTHREAD_MUTEX_INITIALIZER;
– Dichiarazione dinamica:
pthread_mutex_init()
46
47. Concorrenza thread
• Signature: int pthread_mutex_init
(pthread_mutex_t *mutex, const
pthread_mutex_attr_t *mutexattr);
– Descrizione:
♦ Inizializza il mutex puntato da mutex con gli
attributi puntati di mutexattr
♦ Il mutex è UNLOCKED (risorsa libera)
– Ingresso:
♦ un puntatore ad una struttura
pthread_mutex_t
♦ un puntatore ad una struttura
pthread_mutex_attr_t
– Ritorno:
♦ Sempre 0 47
48. Concorrenza thread
• Signature: int pthread_mutex_destroy
(pthread_mutex_t *mutex);
– Descrizione:
♦ Resetta lo stato del mutex puntato da mutex
– Ingresso:
♦ un puntatore ad una struttura
pthread_mutex_t
– Ritorno:
♦ 0: -> tutto OK
♦ !=0: il mutex è attualmente bloccato
48
49. Concorrenza thread
• Signature: int pthread_mutex_lock
(pthread_mutex_t *mutex);
– Descrizione:
♦ Prova ad acquisire un lock su mutex
♦ Se mutex=UNLOCKED, lo acquisisce e torna
♦ Se mutex=LOCKED, si blocca fino a quando la
risorsa non si libera
– Ingresso:
♦ un puntatore ad una struttura pthread_mutex_t
– Ritorno:
♦ 0: -> tutto OK
♦ !=0: mutex non inizializzato o già bloccato dallo
stesso thread
49
50. Concorrenza thread
• Signature: int pthread_mutex_trylock
(pthread_mutex_t *mutex);
– Descrizione:
♦ Provaad acquisire un lock su mutex
♦ Se mutex=UNLOCKED, lo acquisisce e torna
♦ Se mutex=LOCKED, ritorna e non si blocca
– Ingresso:
♦ un puntatore ad una struttura pthread_mutex_t
– Ritorno:
♦ 0: -> tutto OK
♦ !=0: mutex non inizializzato, già bloccato dallo
stesso thread, già bloccato da un altro thread
50
51. Concorrenza thread
• Signature: int pthread_mutex_unlock
(pthread_mutex_t *mutex);
– Descrizione:
♦ Rilascia
la risorsa associata al mutex
♦ Reimposta il mutex ad UNLOCKED
– Ingresso:
♦ un puntatore ad una struttura pthread_mutex_t
– Ritorno:
♦ 0: -> tutto OK
♦ !=0: mutex non inizializzato, già bloccato dallo
stesso thread, già bloccato da un altro thread
51
52. Variabili condizione
• Le variabili condizione costituiscono un
ulteriore meccanismo per la sincronizzazione
fra thread
• Idea: associare eventi al valore di alcune
variabili
– Una variabile assume un valore->scatta un
evento
– Un'altra variabile, detta variabile condizione,
viene usata per segnalare l'evento
– Callback: gestione asincrona di eventi tramite
invocazione di funzioni
• Senza le variabili di condizione, un thread deve
continuamente controllare (poll) l'arrivo di eventi,
sprecando inutilmente risorse di calcolo 52
53. Variabili condizione
• Scenario tipico di utilizzo - variabili condizione
• Tre thread:
– Thread Main: thread di controllo che schedula i
thread di lavoro A e B
– Thread A: lavora fino ad un certo punto, poi si
ferma in attesa di un evento
– Thread B: lavora fino ad un certo punto, poi
scatena l'evento sul quale sta aspettando A
• Che funzioni eseguono i tre thread?
53
54. Variabili condizione
• Thread Main:
– Dichiara ed inizializza (strutture) dati globali che
necessitano di sincronizzazione
– Dichiara ed inizializza un oggetto di tipo
“variabile condizione”
– Dichiara ed inizializza un mutex associato alla
variabile condizione
– Crea i thread A e B
– Join dei thread A e B
54
55. Variabili condizione
• Thread A:
– Lavora fino a quando non si deve interrompere,
in attesa che una condizione si verifichi
– Acquisisce il lock sul mutex
– Si blocca (pthread_cond_wait()) fino a quando
non si verifica l'evento, segnalato da un altro
thread (Thread B)
– pthread_cond_wait() sblocca automaticamente
il mutex, che può essere utilizzato dall'altro
thread per acquisire uso esclusivo sulla
variabile che rappresenta l'evento
– Quando arriva il segnale, Thread A si sveglia ed
il mutex viene di nuovo assegnato a lui
– Thread A rilascia esplicitamente il mutex 55
56. Variabili condizione
• Thread B:
– Lavora
– Acquisisce il lock sul mutex
– Cambia il valore della variabile su cui è bloccato
Thread A
– Se il valore della variabile è tale da scatenare un
evento, segnala Thread A tramite una variabile
condizione
– Rilascia esplicitamente il mutex
56
57. Variabili condizione
• Rappresentate dal tipo di dato opaco
pthread_cond_t
• Devono essere inizializzate prima di poter
essere utilizzate
• Possono specificare dei propri attributi
• L'inizializzazione avviene in due modi distinti:
– Inizializzazione statica:
pthread_cond_t myconvar =
PTHREAD_COND_INITIALIZER;
– Inizializzazione dinamica:
pthread_cond_init()
57
58. Variabili condizione
• Signature: int pthread_cond_init
(pthread_cond_t *cond, const
pthread_condattr_t *cond_attr);
– Descrizione:
♦ Inizializza la variabile condizione cond
utilizzando gli attributi cond_attr (NULL per
default)
– Ingresso:
♦ un puntatore ad una struttura
pthread_cond_t
♦ un puntatore ad una struttura
pthread_condattr_t
– Ritorno:
♦ Sempre 0 58
59. Variabili condizione
• Signature: int pthread_cond_destroy
(pthread_cond_t *cond);
– Descrizione:
♦ Resetta una variabile condizione cond,
rilasciando le risorse che potrebbe avere
allocato
– Ingresso:
♦ un puntatore ad una struttura
pthread_cond_t
– Ritorno:
♦ 0: -> tutto OK
♦ !=0: la variabile condizione è attualmente
utilizzata da un qualche thread
59
60. Variabili condizione
• Signature: int pthread_condattr_init
(pthread_condattr_t *attr);
– Descrizione: inizializza una struttura
pthread_condattr_t
– Ingresso:
♦ un puntatore ad una struttura
pthread_condattr_t
– Ritorno:
♦ Sempre 0
60
61. Variabili condizione
• Signature: int pthread_condattr_init
(pthread_condattr_t *attr);
– Descrizione: inizializza una struttura
pthread_condattr_t
– Ingresso:
♦ un puntatore ad una struttura
pthread_condattr_t
– Ritorno:
♦ Sempre 0
61
62. Variabili condizione
• Signature: int pthread_condattr_destroy
(pthread_condattr_t *attr);
– Descrizione: resetta una struttura
pthread_condattr_t
– Ingresso:
♦ un puntatore ad una struttura
pthread_condattr_t
– Ritorno:
♦ Sempre 0
62
63. Variabili condizione
• Signature: int pthread_cond_wait
(pthread_cond_t *cond, pthread_mutex_t
*mutex);
– Descrizione:
♦ Blocca il thread invocante fino a quando non
viene segnalata la condizione cond
♦ Deve essere invocata con mutex bloccato
(altrimenti un thread potrebbe segnalare la
condizione prima che un altro possa
ascoltarla); il mutex viene automaticamente
sbloccato al termine della chiamata
♦ Quando si verifica la condizione, il thread
viene svegliato e mutex viene acquisito di
nuovo (ricordatevi di rilasciarlo!)
63
64. Variabili condizione
• Signature: int pthread_cond_wait
(pthread_cond_t *cond, pthread_mutex_t
*mutex);
– Ingresso:
♦ Un puntatore alla struttura pthread_cont_t
che rappresenta la variabile condizione su
cui aspettare
♦ Un puntatore alla struttura pthread_mutex_t
che rappresenta il mutex associato alla
variabile condizione
– Ritorno:
♦ Sempre 0
64
65. Variabili condizione
• Signature: int pthread_cond_signal
(pthread_cond_t *cond);
– Descrizione:
♦ Segnala (risveglia) un altro thread in seguito
al verificarsi di una data condizione
♦ Più thread possono aspettare una data
condizione; pthread_cond_signal() ne
risveglia solamente uno
– Ingresso:
♦ Un puntatore alla struttura pthread_cont_t
che rappresenta la variabile condizione su
cui aspettare
– Ritorno:
♦ Sempre 0 65
66. Variabili condizione
• Signature: int pthread_cond_broadcast
(pthread_cond_t *cond);
– Descrizione:
♦ Segnala (risveglia) un insieme di thread in
seguito al verificarsi di una data condizione
♦ Più thread possono aspettare una data
condizione; pthread_cond_broadcast() li
risveglia tutti
– Ingresso:
♦ Un puntatore alla struttura pthread_cont_t
che rappresenta la variabile condizione su
cui aspettare
– Ritorno:
♦ Sempre 0 66