...

Sincronizzazione di thread POSIX

by user

on
Category: Documents
21

views

Report

Comments

Transcript

Sincronizzazione di thread POSIX
Sincronizzazione di thread POSIX
Sincronizzazione
●
I thread condividono la memoria
●
Rischio di race condition
●
Necessari meccanismi di sincronizzazione
–
mutex (semaforo binario)
–
condition variable
I mutex
●
●
Un mutex è un semaforo binario (rosso o verde)
Un mutex è mantenuto in una struttura pthread_mutex_t
●
Va allocata e inizializzata una tale struttura
●
Per inizializzare:
–
se la struttura è allocata staticamente: pthread_mutex_t c = PTHREAD_MUTEX_INITIALIZER
–
se la struttura è allocata dinamicamente: chiamare
pthread_mutex_init (vedere dopo)
Inizializzare e distruggere un mutex
int pthread_mutex_init(
pthread_mutex_t *mutex,
const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
●
inizializza e distrugge un mutex, rispettivamente
●
restituiscono 0 se OK, un codice d'errore altrimenti
●
attr può essere NULL (attributi di default)
4
Usare i mutex
int pthread_mutex_lock
(pthread_mutex_t *mutex);
int pthread_mutex_trylock (pthread_mutex_t *mutex);
int pthread_mutex_unlock (pthread_mutex_t *mutex);
●
acquisiscono e rilasciano il semaforo
●
restituiscono 0 se OK, un codice d'errore altrimenti
●
se il semaforo è occupato...
–
...lock blocca il thread finché il semaforo si libera
–
...trylock invece restituisce subito l'errore EBUSY
5
Deadlock
●
●
Condizione di attesa ciclica
Soluzione base: acquisire i mutex sempre nello stesso ordine
6
Precauzioni
●
Non si può acquisire un mutex più di una volta
–
●
Non si può rilasciare un mutex che non si possiede
–
●
se chiamo lock su un mutex che già posseggo, vado in deadlock
se chiamo unlock su un mutex che non posseggo, il comportamento non è specificato
Queste regole si possono cambiare usano gli attributi del mutex
7
Esercizio 1
●
Eliminare le race condition dall'Esercizio 1 relativo ai thread POSIX
8
Le condition variable
●
●
Servono per attendere che una condizione si verifichi, escludendo race conditions
Una condition variable è mantenuta in una struttura
pthread_cond_t
●
Va allocata e inizializzata una tale struttura
●
Per inizializzare:
–
se la struttura è allocata staticamente: pthread_cond_t c = PTHREAD_COND_INITIALIZER
–
se la struttura è allocata dinamicamente: chiamare pthread_cond_init (vedere dopo)
9
Inizializzare e distruggere
una condition variable
int pthread_cond_init( pthread_cond_t *cond,
const pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cond);
●
inizializza e distrugge una condition variable, rispettivamente
●
restituiscono 0 se OK, un codice d'errore altrimenti
●
attr può essere NULL (attributi di default)
10
Usare una condition variable
●
thread che aspetta una condizione
●
thread che rende la condizione vera
mutex_lock(m)
mutex_lock(m)
while (condizione falsa)
rendi la condizione vera
cond_wait(c, m)
fa' qualcosa
mutex_unlock(m)
cond_broadcast(c)
mutex_unlock(m)
11
Attendere una condition variable
int pthread_cond_wait(pthread_cond_t *cond,
pthread_mutex_t*mutex);
●
attende che cond sia segnalata come vera
●
restituisce 0 se OK, un codice d'errore altrimenti
●
il mutex protegge la condizione
–
deve essere acquisito prima di chiamare cond_wait
–
durante l'attesa, cond_wait rilascia il mutex
–
finita l'attesa, cond_wait riprende il mutex
12
Segnalare una condition variable
int pthread_cond_broadcast(pthread_cond_t
*cond);
●
segnala che la condizione cond è vera
●
sblocca tutti i thread che stanno aspettando la condizione
●
restituisce 0 se OK, un codice d'errore altrimenti
●
va chiamata mentre si possiede il mutex associato
13
Esercizio 2
●
Usando mutex e condition variable, implementare un semaforo con la seguente interfaccia:
–
sem_init(int n)
inizializza il semaforo con valore n
–
sem_wait()
decrementa il semaforo (bloccandosi se il valore e' zero)
–
sem_post()
incrementa il semaforo di 1
14
Esercizio 3
●
●
●
●
realizzare un programma che accetta da riga di comando due numeri interi n ed m, e crea n produttori ed m consumatori
produttori e consumatori condividono un array di 100 interi
ogni produttore aspetta un numero casuale di secondi tra 1 e 10, e poi produce (cioè inserisce nell'array) da 1 a 5 numeri casuali. Se il produttore trova l'array pieno, salta il turno
ogni consumatore aspetta che ci sia un numero da consumare, e poi stampa a video il proprio tid e il valore consumato
15
Dati globali di un thread
●
●
Come fa un thread ad avere dati globali?
Non può usare una variabile globale, perché condivisa
–
●
●
ci vorrebbe una variabile globale per ogni thread: complicato
Deve usare una variabile locale, che viene passata a tutte le funzioni chiamate dal thread
Oppure...thread­specific data
16
Thread­specific data
●
associare a una stessa chiave dati diversi per ciascun thread
thread principale
pthread_key_t chiave; // variabile globale
inizializza la chiave
crea i thread
thread 1
pthread_setspecific(chiave, malloc(...));
...
void *p = pthread_getspecific(chiave)
thread 2
pthread_setspecific(chiave, malloc(...));
...
void *p = pthread_getspecific(chiave)
17
Creare una chiave
int pthread_key_create(pthread_key_t *key,
void (*destructor)(void *));
●
crea una chiave per dati privati
●
key è l'indirizzo della chiave da inizializzare
●
●
destructor è un puntatore alla funzione che deve essere chiamata alla terminazione del thread
restituisce 0 se OK, un codice d'errore altrimenti
18
Usare una chiave
int pthread_setspecific(pthread_key_t *key,
const void* val);
●
associa l'indirizzo val alla chiave key, per il thread corrente
●
restituisce 0 se OK, un codice d'errore altrimenti
void* pthread_getspecific(pthread_key_t *key);
●
restituisce l'indirizzo associato alla chiave key nel thread corrente
–
restituisce NULL se nessun indirizzo è stato associato a key
19
Esercizio 4
●
●
●
scrivere un programma che prende da riga di comando un intero n, imposta un gestore per il segnale SIGUSR1 e poi crea n thread
ciascun thread aspetta un numero casuale di secondi tra 1 e 5, poi invia il segnale SIGUSR1 a uno a caso tra i suoi fratelli thread (e poi ripete il procedimento)
il gestore del segnale stampa a video il tid del thread corrente e il numero totale di segnali SIGUSR1 ricevuti da quel thread fino a quel momento
20
Fly UP