Un thread, o processo leggero, è un flusso di controllo sequenziale di un programma.
La coppia processo+threads Realizza la separazione tra concorrenza e protezione.
Nei sistemi Unix, un thread:
Dal punto di vista di un programmatore, un thread può essere visto come una procedura che viene eseguita indipendentemente dal programma principale.
I processi contengono informazioni sulle risorse del programma e lo stato di esecuzione:
I thread possono essere schedulati ed eseguiti indipendente perché possiedono i loro:
I thread che eseguono in uno stesso processo condividono le risorse del processo, per cui:
Manager/Workers: un thread, il manager, riceve in input i comandi e assegna i lavori ad altri thread, i workers.
Pipeline: un task è suddiviso in una serie di operazioni più semplici, che possono essere eseguite in serie, ma concorrentemente, da diversi thread.
Peer: simile al modello Manager/Workers, ma una volta che il thread principale assegna il lavoro agli altri thread, partecipa attivamente anch’esso nel lavoro.
Breve storia
I PThreads sono stati definiti come un insieme di tipi e procedure implementate in C.
Sono composti da un file pthread.h e una libreria.
Principalmente, per il guadagno in prestazioni.
Ma anche, la comunicazione inter-thread è molto più efficiente e semplice da usare della comunicazione inter-processo.
Gestione dei Thread: creazione, distruzione e join di thread.
Gestione dei Mutex: creazione, distruzione, lock e unlock di variabili di mutua esclusione (mutex) per la gestione di sezioni critiche.
Gestione delle Condition Variables: creazione, distruzione, wait e signal su variabili condition definite dal programmatore.
pthread_create (thread,attr,start_r,arg)
Crea un nuovo thread e lo rende eseguibile.
thread
(output): di tipo pthread_t
, è un identificatore del thread creato;attr
(input): di tipo pthread_attr_t
, serve a settare gli attributi del thread;start_r
(input): puntatore alla funzione C (starting routine) che verrà eseguita una volta che il thread è creato;arg
(input): argomento che può essere passato alla funzione C (ne va fatto il casting a void *
).Un thread può terminare per diversi motivi:
pthread_exit()
;pthread_cancel()
;pthread_exit (status)
La pthread_create
consente di passare un singolo argomento di tipo void *
;
Per passare più di un argomento al thread, si può definire e passare una struct, facendone il casting a void
*:
struct dati {
int dato1;
char dato2;
}
...
dati *d; d->dato1=10; d->dato2=‘c';
pthread_create(&id,NULL,start_f,(void *) d)
Nel thread sarà sufficiente effettuare il casting inverso:
dati* miei_dati = (struct dati *) d;
Il Join è un modo per sincronizzare più thread.
La chiamata pthread_join(threadId, status)
blocca il chiamante finché il thread threadId specificato non termina;
La chiamata consente di ricavare lo stato di uscita del thread (status
) specificato nella pthread_exit();
Un thread deve essere dichiarato come “joinable” affinché su di esso si possa effettuare l’operazione di join:
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
...
pthread_create(&id,&attr, start_r, (void *) data);
...
pthread_join(id, (void **) &status);
pthread_mutex_init (mutex,attr)
mutex
(output): di tipo pthread_mutex_t
è un identificatore del mutex creato;attr
(input): per settare gli attributi del mutex;pthread_mutex_destroy (mutex)
pthread_mutex_lock (mutex)
pthread_mutex_trylock (mutex)
pthread_mutex_unlock (mutex)
Si vuole calcolare il prodotto scalare di due vettori di reali.
I vettori possono essere condivisi tra più thread.
Ogni thread calcola il prodotto scalare tra una parte dei due vettori, ed aggiorna una variabile condivisa contenente il risultato.
Rappresentano ancora un altro mezzo di sincronizzazione, oltre che i Join e i mutex.
La sincronizzazione con CV si basa sui valori correnti dei dati (una condizione).
Vanno sempre usate in congiunzione con un mutex, realizzando un costrutto Monitor.
pthread_cond_init (condition,attr)
condition
(output): di tipo pthread_cond_t
è un identificatore della CV creata;attr
(input): per settare gli attributi della CV.pthread_cond_destroy (condition)
pthread_cond_wait (condition,mutex)
enter_monitor
→ pthread_mutex_lock();
wait_cond
→ pthread_cond_wait()
: rilascia automaticamente il mutex e blocca il chiamante;leave_monitor
→ Il programmatore è responsabile di sbloccare il mutex con una pthread_mutex_unlock().pthread_cond_signal (condition)
1. Introduzione ai Sistemi Operativi
5. Scheduling nei sistemi mono-processore
6. Threads, SMP
8. Scheduling Multiprocessore e Real-Time
9. Gestione dei processi nei sistemi operativi Unix/Linux e Window...
10. Introduzione alla Programmazione Concorrente
11. Sincronizzazione nel modello ad ambiente globale
12. Problemi di cooperazione nel modello ad ambiente globale
14. Sincronizzazione nel modello ad ambiente locale
15. Deadlock
16. Programmazione Multithread
18. Memoria Virtuale
20. Il File System
21. Primitive di sincronizzazione nel kernel Linux
22. Esercitazione: System call per la gestione dei processi
23. Esercitazione: Inteprocess Communication e Shared Memory
24. Esercitazione: System Call per la gestione dei semafori in Linu...
25. Esercitazione: Problema dei Produttori e dei Consumatori
26. Posix Threads