22.01.2014 Views

(fork, wait, ...) , Thread (pthread) - lucidi - Dipartimento di Ingegneria ...

(fork, wait, ...) , Thread (pthread) - lucidi - Dipartimento di Ingegneria ...

(fork, wait, ...) , Thread (pthread) - lucidi - Dipartimento di Ingegneria ...

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Sistemi Operativi<br />

Corso <strong>di</strong> Laurea Triennale<br />

in <strong>Ingegneria</strong> Informatica<br />

Esercitazione 6<br />

• Programmazione concorrente<br />

• Ripasso processi<br />

• <strong>Thread</strong>:<br />

• Join, mutex, con<strong>di</strong>tion<br />

daniel.cesarini@for.unipi.it<br />

1


Domande sulle<br />

lezioni passate


Sommario<br />

Programmazione concorrente<br />

Processi<br />

Operazioni sui processi<br />

Creazione, comunicazione, ...<br />

<strong>Thread</strong> POSIX<br />

Operazioni sui <strong>Thread</strong><br />

Creazione, terminazione, join<br />

Sincronizzazione<br />

Semafori<br />

Variabili con<strong>di</strong>tion<br />

Aspetti preliminari dei thread POSIX 3


Processi Unix


System call per i processi<br />

Creazione <strong>di</strong> processi: <strong>fork</strong>()<br />

Terminazione: exit()<br />

Sospensione in attesa della<br />

terminazione <strong>di</strong> figli: <strong>wait</strong>()<br />

Sostituzione <strong>di</strong> co<strong>di</strong>ce e dati: exec..()<br />

Aspetti preliminari dei thread POSIX 5


Creazione <strong>di</strong> processi: <strong>fork</strong>() - 1<br />

<strong>fork</strong>() consente a un processo <strong>di</strong><br />

generare un processo figlio:<br />

Padre e figlio con<strong>di</strong>vidono lo stesso co<strong>di</strong>ce<br />

Il figlio ere<strong>di</strong>ta una copia dei dati (<strong>di</strong> utente<br />

e <strong>di</strong> kernel) del padre<br />

padre<br />

<strong>fork</strong>( )<br />

figlio<br />

Aspetti preliminari dei thread POSIX 6


Relazione padre-figlio - <strong>fork</strong>()<br />

Concorrenza: padre e figlio procedono in<br />

parallelo<br />

Il co<strong>di</strong>ce è con<strong>di</strong>viso<br />

Lo spazio degli in<strong>di</strong>rizzi è duplicato:<br />

Ogni variabile del figlio è inizializzata con il valore<br />

assegnatole dal padre prima della <strong>fork</strong>()<br />

La user structure è duplicata:<br />

Le risorse allocate al padre prima della generazione sono<br />

con<strong>di</strong>vise col figlio<br />

Stessa gestione dei segnali per padre e figlio<br />

Il figlio nasce con lo stesso Program Counter del padre: la<br />

prima istruzione eseguita è quella che segue<br />

imme<strong>di</strong>atamente la <strong>fork</strong>()<br />

Aspetti preliminari dei thread POSIX 7


Esempio <strong>di</strong> <strong>fork</strong>() ed execl()<br />

#include <br />

#include <br />

#include <br />

int int main main (int (int argc, char char * argv[]) {<br />

int int pid, pid, status;<br />

pid=<strong>fork</strong>();<br />

if if (pid==0) {<br />

execl("/bin/ls", "ls", "-l", (char *) *) 0); 0);<br />

printf("exec fallita!\n");<br />

exit(1);<br />

}<br />

else else if if (pid>0) {<br />

pid=<strong>wait</strong>(&status);<br />

/* /* Gestione dello stato */ */<br />

}<br />

else else printf("<strong>fork</strong> fallita!\n");<br />

}<br />

Aspetti preliminari dei thread POSIX 8


Co<strong>di</strong>ce nella cartella esempi<br />

<strong>fork</strong>1.c<br />

Called once, returns twice<br />

<strong>fork</strong>2.c<br />

Uso <strong>di</strong> getpid() e getppid()<br />

exec1.c<br />

Uso <strong>di</strong> execv (path ...)<br />

fdtest1.c<br />

Read e Write dagli stessi file<br />

Aspetti preliminari dei thread POSIX 9


Co<strong>di</strong>ce nella cartella esempi<br />

<strong>di</strong>e1.c<br />

Padre termina prima del figlio ( ./<strong>di</strong>e)<br />

<strong>di</strong>e2.c<br />

Figlio termina prima del padre ( ./<strong>di</strong>e2 &)<br />

<strong>di</strong>e3.c<br />

Signal handler in azione ( ./<strong>di</strong>e3 &)<br />

Aspetti preliminari dei thread POSIX 10


<strong>Thread</strong> POSIX<br />

thread = filo


<strong>Thread</strong> POSIX<br />

Introduzione ai thread POSIX<br />

operazioni elementari sui thread<br />

Sincronizzazione<br />

Semafori<br />

semafori <strong>di</strong> mutua esclusione<br />

semafori generali<br />

utilizzo ed esempi<br />

Variabili con<strong>di</strong>tion<br />

generalità<br />

utilizzo ed esempi<br />

Aspetti preliminari dei thread POSIX 12


<strong>Thread</strong> POSIX: aspetti<br />

preliminari


Processo vs <strong>Thread</strong> (2 <strong>di</strong> 2)<br />

I thread eseguono su memoria con<strong>di</strong>visa nell’ambito dello stesso processo,<br />

quando un thread viene creato con<strong>di</strong>vide il suo spazio <strong>di</strong> memoria con gli<br />

altri thread che fanno parte del processo<br />

Sono anche chiamati lightweight process o processi leggeri perché<br />

possiedono un contesto più snello rispetto ai processi<br />

Aspetti preliminari dei thread POSIX 14


<strong>Thread</strong><br />

<strong>Thread</strong><br />

è l’unità granulare in cui un processo può essere<br />

sud<strong>di</strong>viso e che può essere eseguito in parallelo<br />

ad altri thread<br />

è parte del processo che viene eseguita in<br />

maniera concorrente ed in<strong>di</strong>pendente<br />

internamente al processo stesso<br />

insieme <strong>di</strong> istruzioni che vengono eseguite in<br />

modo in<strong>di</strong>pendente rispetto al main<br />

Stato <strong>di</strong> un thread<br />

stack<br />

registri<br />

proprietà <strong>di</strong> scheduling<br />

stato dei segnali<br />

dati privati<br />

Aspetti preliminari dei thread POSIX 15


Funzioni delle API per Pthread<br />

Le API per Pthread <strong>di</strong>stinguono le funzioni in<br />

3 gruppi:<br />

<strong>Thread</strong> management<br />

funzioni per creare, eliminare, attendere la fine dei<br />

<strong>pthread</strong><br />

Mutexes:<br />

funzioni per supportare un tipo <strong>di</strong> sincronizzazione<br />

semplice chiamata “mutex” (mutua esclusione).<br />

funzioni per creare ed eliminare la struttura per la<br />

mutua esclusione <strong>di</strong> una risorsa, acquisire e rilasciare<br />

tale risorsa.<br />

Con<strong>di</strong>tion variables:<br />

funzioni a supporto <strong>di</strong> una sincronizzazione più<br />

complessa, <strong>di</strong>pendente dal valore <strong>di</strong> variabili, secondo<br />

i mo<strong>di</strong> definite dal programmatore.<br />

funzioni per creare ed eliminare la struttura per la<br />

sincronizzazione, per attendere e segnalare le<br />

mo<strong>di</strong>fiche delle variabili.<br />

Aspetti preliminari dei thread POSIX 16


Utilizzo<br />

includere l’header della libreria che<br />

contiene le definizioni dei <strong>pthread</strong><br />

#include <br />

Per interpretare correttamente i messaggi <strong>di</strong><br />

errore è necessario anche includere l’header<br />

<br />

compilare specificando la libreria<br />

gcc -l<strong>pthread</strong><br />

Libreria <strong>pthread</strong> (lib<strong>pthread</strong>) l<strong>pthread</strong><br />

Per ulteriori informazioni sulla compilazione fare<br />

riferimento alla documentazione della<br />

piattaforma utilizzata man <strong>pthread</strong> o man<br />

<strong>pthread</strong>s<br />

Aspetti preliminari dei thread POSIX 17


Convenzione sui nomi delle funzioni<br />

Gli identificatori della libreria dei Pthread iniziano<br />

con <strong>pthread</strong>_<br />

<strong>pthread</strong>_<br />

in<strong>di</strong>ca la gestione dei thread in generale<br />

<strong>pthread</strong>_attr_<br />

funzioni per gestire proprietà dei thread<br />

<strong>pthread</strong>_mutex_<br />

gestione della mutua esclusione<br />

<strong>pthread</strong>_mutexattr_<br />

proprietà delle strutture per la mutua esclusione<br />

<strong>pthread</strong>_cond_<br />

gestione delle variabili <strong>di</strong> con<strong>di</strong>zione<br />

<strong>pthread</strong>_condattr_<br />

proprietà delle variabili <strong>di</strong> con<strong>di</strong>zione<br />

<strong>pthread</strong>_key_<br />

dati speciali dei thread<br />

Aspetti preliminari dei thread POSIX 18


Gestione dei thread


Tipi definiti nella libreria <strong>pthread</strong><br />

All’interno <strong>di</strong> un programma un thread è<br />

rappresentato da un identificatore<br />

tipo opaco <strong>pthread</strong>_t<br />

Attributi <strong>di</strong> un thread<br />

tipo opaco <strong>pthread</strong>_attr_t<br />

tipo opaco: si definiscono così strutture ed altri oggetti usati da una libreria, la cui<br />

struttura interna non deve essere vista dal programma chiamante (da cui il<br />

nome) che li deve utilizzare solo attraverso dalle opportune funzioni <strong>di</strong> gestione.<br />

Aspetti preliminari dei thread POSIX 20


Identificatore del thread<br />

Processo: process id (pid)<br />

pid_t<br />

<strong>Thread</strong>: thread id (tid) <strong>pthread</strong>_t<br />

<strong>pthread</strong>_t <strong>pthread</strong>_self( void )<br />

restituisce il tid del thread chiamante<br />

Aspetti preliminari dei thread POSIX 21


Confronto tra thread<br />

int int <strong>pthread</strong>_equal( <strong>pthread</strong>_t t1, t1, <strong>pthread</strong>_t t2 t2 )<br />

confronta i due identificatori <strong>di</strong> thread.<br />

1 se i due identificatori sono uguali<br />

Aspetti preliminari dei thread POSIX 22


Creazione <strong>di</strong> un thread (1 <strong>di</strong> 2)<br />

int int <strong>pthread</strong>_create( <strong>pthread</strong>_t *thread,<br />

const <strong>pthread</strong>_attr_t *attr,<br />

void *(*start_routine)(void *), *),<br />

void *arg )<br />

crea una thread e lo rende eseguibile, cioè lo<br />

mette a <strong>di</strong>sposizione dello scheduler per<br />

farlo partire ().<br />

Non è preve<strong>di</strong>bile<br />

il momento dell'attivazione<br />

del thread<br />

Aspetti preliminari dei thread POSIX 23


Creazione <strong>di</strong> un thread (2 <strong>di</strong> 2)<br />

<br />

<br />

<strong>pthread</strong>_t *thread<br />

puntatore ad un identificatore <strong>di</strong> thread in cui verrà scritto<br />

l’identificatore univoco del thread creato (se creato con<br />

successo)<br />

const <strong>pthread</strong>_attr_t *attr<br />

attributi del processo da creare: può in<strong>di</strong>care le caratteristiche<br />

del thread riguardo alle operazioni <strong>di</strong> join o allo scheduling<br />

se NULL usa valori <strong>di</strong> default<br />

void *(*start_routine)(void *)<br />

è il nome (in<strong>di</strong>rizzo) della funzione da eseguire alla creazione del<br />

thread<br />

<br />

<br />

void *arg<br />

puntatore che viene passato come argomento a<br />

start_routine.<br />

Valore <strong>di</strong> ritorno<br />

0 in assenza <strong>di</strong> errore<br />

<strong>di</strong>verso da zero altrimenti<br />

attributi errati<br />

mancanza <strong>di</strong> risorse<br />

Aspetti preliminari dei thread POSIX 24


Terminazione <strong>di</strong> un thread<br />

void <strong>pthread</strong>_exit( void *value_ptr )<br />

<br />

<br />

<br />

<br />

Termina l’esecuzione del thread da cui viene chiamata<br />

Il sistema libera le risorse allocate al thread.<br />

Se il main termina prima che i thread da lui creati siano<br />

terminati e non chiama la funzione <strong>pthread</strong>_exit, allora<br />

tutti i thread sono terminati. Se invece il main chiama<br />

<strong>pthread</strong>_exit allora i thread possono continuare a vivere<br />

fino alla loro terminazione.<br />

void *value_ptr<br />

valore <strong>di</strong> ritorno del thread consultabile da altri thread<br />

attraverso la funzione <strong>pthread</strong>_join<br />

Aspetti preliminari dei thread POSIX 25


Esempio 1: creazione e terminazione<br />

(1 <strong>di</strong> 2)<br />

/* /* Include Include */ */<br />

#include #include <br />

<br />

#include #include <br />

<br />

#include #include <br />

<br />

#define #define NUM_THREADS NUM_THREADS 5<br />

/* /* Corpo Corpo del del thread thread */ */<br />

void void *PrintHello(void *PrintHello(void *num) *num) {<br />

printf("\n%d: printf("\n%d: Hello Hello World!\n", World!\n", num); num);<br />

<strong>pthread</strong>_exit(NULL);<br />

<strong>pthread</strong>_exit(NULL);<br />

}}<br />

Continua <br />

Aspetti preliminari dei thread POSIX 26


Esempio 1: creazione e terminazione<br />

(2 <strong>di</strong> 2)<br />

/* /* Programma Programma */ */<br />

int int main main (int (int argc, argc, char char *argv[]) *argv[])<br />

{<br />

<strong>pthread</strong>_t <strong>pthread</strong>_t threads[NUM_THREADS];<br />

threads[NUM_THREADS];<br />

int int rc, rc, t; t;<br />

for(t=0; for(t=0; t


Passaggio parametri (1 <strong>di</strong> 3)<br />

La <strong>pthread</strong>_create prevede un puntatore per il<br />

passaggio dei parametri al thread nel momento<br />

in cui comincia l’esecuzione.<br />

Si ponga attenzione nel caso il thread debba<br />

mo<strong>di</strong>ficare i parametri, oppure il chiamante<br />

debba mo<strong>di</strong>ficare i parametri, potrebbero<br />

insorgere problemi, meglio de<strong>di</strong>care una<br />

struttura dati ad hoc, per il passaggio.<br />

Aspetti preliminari dei thread POSIX 28


Passaggio parametri (2 <strong>di</strong> 3)<br />

Per riferimento con un cast a void*<br />

Esempio (errato)<br />

il ciclo mo<strong>di</strong>fica il contenuto dell’in<strong>di</strong>rizzo passato<br />

come parametro<br />

int<br />

int<br />

rc,<br />

rc,<br />

t;<br />

t;<br />

for(t=0; for(t=0; t


Passaggio parametri (3 <strong>di</strong> 3)<br />

Esempio (corretto)<br />

struttura dati univoca per ogni thread<br />

int int *taskids[NUM_THREADS];<br />

*taskids[NUM_THREADS];<br />

for(t=0; for(t=0; t


Esempio 2 errato: passaggio parametri (1<br />

<strong>di</strong> 2)<br />

/* /* Include Include */ */<br />

#include #include <br />

<br />

#include #include <br />

#include #include <br />

<br />

#define<br />

#define<br />

NUM_THREADS<br />

NUM_THREADS<br />

5<br />

/* /* Corpo Corpo del del thread thread */ */<br />

void void *PrintHello(void *PrintHello(void *num) *num) {<br />

printf("\n%d: printf("\n%d: Hello Hello World!\n", World!\n", *(int *(int *) *) num); num);<br />

<strong>pthread</strong>_exit(NULL);<br />

<strong>pthread</strong>_exit(NULL);<br />

}<br />

Aspetti preliminari dei thread POSIX 31


Esempio 2 errato : passaggio parametri (2<br />

<strong>di</strong> 2)<br />

/* /* Programma Programma */ */<br />

int int main main (int (int argc, argc, char char *argv[]) *argv[])<br />

{<br />

<strong>pthread</strong>_t <strong>pthread</strong>_t threads[NUM_THREADS];<br />

threads[NUM_THREADS];<br />

int int rc, rc, t; t;<br />

}<br />

for(t=0; for(t=0; t


Esempio 2 : passaggio parametri (1<br />

<strong>di</strong> 2)<br />

/* /* Include Include */ */<br />

#include #include <br />

<br />

#include #include <br />

#include #include <br />

<br />

#define<br />

#define<br />

NUM_THREADS<br />

NUM_THREADS<br />

5<br />

/* /* Corpo Corpo del del thread thread */ */<br />

void void *PrintHello(void *PrintHello(void *num) *num) {<br />

printf("\n%d: printf("\n%d: Hello Hello World!\n", World!\n", *(int *(int *) *) num); num);<br />

<strong>pthread</strong>_exit(NULL);<br />

<strong>pthread</strong>_exit(NULL);<br />

}<br />

Aspetti preliminari dei thread POSIX 33


Esempio 2 : passaggio parametri (2<br />

<strong>di</strong> 2)<br />

/* /* Programma Programma */ */<br />

int int main main (int (int argc, argc, char char *argv[]) *argv[])<br />

{<br />

<strong>pthread</strong>_t <strong>pthread</strong>_t threads[NUM_THREADS];<br />

threads[NUM_THREADS];<br />

int int rc, rc, t; t;<br />

int int *taskids[NUM_THREADS];<br />

*taskids[NUM_THREADS];<br />

for(t=0; for(t=0; t


Esercizi<br />

(parte uno)


Esercizio 1<br />

<strong>pthread</strong>s-1a-simple.c<br />

analizzare l'output<br />

cambiare <strong>pthread</strong>s_exit(NULL) in<br />

return(0)<br />

cosa succede?<br />

aggiungere il passaggio <strong>di</strong> un parametro ai<br />

thread passando a tutti lo stesso valore<br />

<strong>pthread</strong>s-1b-simple.c<br />

cosa cambia rispetto al precedente?<br />

<strong>pthread</strong>s-1c-simple.c<br />

soluzione dell'esercizio precedente<br />

Aspetti preliminari dei thread POSIX 36


<strong>pthread</strong>s-1a-simple.c<br />

#include <br />

#include <br />

#include <br />

#include <br />

#define NUM_THREADS 3<br />

void *thread_function(void* arg){<br />

printf("[<strong>Thread</strong>] Waiting for termination...\n");<br />

sleep(5);<br />

printf("[<strong>Thread</strong>] ...thread finished!\n");<br />

<strong>pthread</strong>_exit(NULL);<br />

}<br />

int main(void){<br />

<strong>pthread</strong>_t tids[NUM_THREADS];<br />

int i, rc;<br />

printf("[Main] Starting...\n");<br />

for (i=0; i


<strong>pthread</strong>s-1b-simple.c (1 <strong>di</strong><br />

2)<br />

#include <br />

#include <br />

#include <br />

#include <br />

#define NUM_THREADS 3<br />

void *thread_function(void* arg){<br />

printf("[<strong>Thread</strong>] Waiting for termination...\n");<br />

sleep(5);<br />

printf("[<strong>Thread</strong>] ...thread finished!\n");<br />

<strong>pthread</strong>_exit(NULL);<br />

}<br />

Continua <br />

Aspetti preliminari dei thread POSIX 38


<strong>pthread</strong>s-1b-simple.c (2 <strong>di</strong><br />

2)<br />

int main(void){<br />

<strong>pthread</strong>_t tids[NUM_THREADS];<br />

int i, rc;<br />

printf("[Main] Starting...\n");<br />

for (i=0; i


Esercizio 2<br />

<strong>pthread</strong>s-2a-args.c<br />

analizzare l'output<br />

mo<strong>di</strong>ficare in modo da ottenere un<br />

funzionamento corretto<br />

<strong>pthread</strong>s-2b-args.c<br />

soluzione dell'esercizio precedente<br />

Aspetti preliminari dei thread POSIX 40


<strong>pthread</strong>s-2a-args.c<br />

#include <br />

#include <br />

#include <br />

#include <br />

#define NUM_THREADS 3<br />

void *thread_function(void* arg)<br />

{<br />

int i = *(int*)arg;<br />

printf("[<strong>Thread</strong> %d] Waiting for termination...\n",i);<br />

sleep(5);<br />

printf("[<strong>Thread</strong> %d] ...thread finished!\n",i);<br />

<strong>pthread</strong>_exit(NULL);<br />

}<br />

int main(void)<br />

{<br />

<strong>pthread</strong>_t tids[NUM_THREADS];<br />

int i, rc;<br />

printf("[Main] Starting...\n");<br />

for (i=0; i


Sincronizzazione<br />

(semplice)


Join tra thread<br />

Forma elementare <strong>di</strong> sincronizzazione<br />

il thread che effettua il join si blocca<br />

finché uno specifico thread non termina<br />

il thread che effettua il join può ottenere lo<br />

stato del thread che termina<br />

Attributo detachstate <strong>di</strong> un thread<br />

specifica se si può invocare o no la<br />

funzione join su un certo thread<br />

un thread è joinable per default<br />

Aspetti preliminari dei thread POSIX 43


Operazione <strong>di</strong> join<br />

int int <strong>pthread</strong>_join( <strong>pthread</strong>_t *thread, void **value )<br />

<br />

<br />

<br />

<strong>pthread</strong>_t *thread<br />

identificatore del thread <strong>di</strong> cui attendere la<br />

terminazione<br />

void **value<br />

valore restituito dal thread che termina<br />

Valore <strong>di</strong> ritorno<br />

0 in caso <strong>di</strong> successo<br />

EINVAL se il thread da attendere non è joinable<br />

ERSCH se non è stato trovato nessun thread<br />

corrispondente all’identificatore specificato<br />

Aspetti preliminari dei thread POSIX 44


Impostazione attributo <strong>di</strong> join<br />

(1 <strong>di</strong> 4)<br />

int int <strong>pthread</strong>_attr_init( <strong>pthread</strong>_attr_t *attr )<br />

Inizializza gli attributi del <strong>pthread</strong><br />

int int <strong>pthread</strong>_attr_destroy ( <strong>pthread</strong>_attr_t *attr)<br />

Dealloca il <strong>pthread</strong><br />

Aspetti preliminari dei thread POSIX 45


Impostazione attributo <strong>di</strong> join<br />

(2 <strong>di</strong> 4)<br />

Un thread può essere:<br />

Joinable: i thread non sono rilasciati<br />

automaticamente ma rimangono come zombie<br />

finchè altri thread non effettuano delle join<br />

Detached: i thread detached sono rilasciati<br />

automaticamente e non possono essere oggetto<br />

<strong>di</strong> join da parte <strong>di</strong> altri thread.<br />

int int <strong>pthread</strong>_attr_setdetachstate( <strong>pthread</strong>_attr_t *attr,<br />

int int detachstate )<br />

<br />

Detach può essere:<br />

PTHREAD_CREATE_DETACHED<br />

PTHREAD_CREATE_JOINABLE.<br />

Aspetti preliminari dei thread POSIX 46


Impostazione attributo <strong>di</strong> join<br />

(3 <strong>di</strong> 4)<br />

/* /* Attributo Attributo */ */<br />

<strong>pthread</strong>_attr_t <strong>pthread</strong>_attr_t attr; attr;<br />

/* /* Inizializzazione Inizializzazione esplicita esplicita dello dello stato stato joinable joinable */ */<br />

<strong>pthread</strong>_attr_init(&attr);<br />

<strong>pthread</strong>_attr_init(&attr);<br />

<strong>pthread</strong>_attr_setdetachstate(&attr,<br />

<strong>pthread</strong>_attr_setdetachstate(&attr,<br />

PTHREAD_CREATE_JOINABLE);<br />

PTHREAD_CREATE_JOINABLE);<br />

... ...<br />

<strong>pthread</strong>_attr_destroy(&attr);<br />

<strong>pthread</strong>_attr_destroy(&attr);<br />

Aspetti preliminari dei thread POSIX 47


Impostazione attributo <strong>di</strong> join<br />

(4 <strong>di</strong> 4)<br />

int int main main (int (int argc, argc, char char *argv[]) *argv[]) {<br />

<strong>pthread</strong>_t <strong>pthread</strong>_t thread[NUM_THREADS];<br />

thread[NUM_THREADS];<br />

... ...<br />

<strong>pthread</strong>_attr_destroy(&attr);<br />

<strong>pthread</strong>_attr_destroy(&attr);<br />

for(t=0; for(t=0; t


Esempio 3: thread join (1 <strong>di</strong> 3)<br />

/* /* Include Include */ */<br />

#include #include <br />

<br />

#include #include <br />

#include<br />

#include<br />

<br />

<br />

#define #define NUM_THREADS NUM_THREADS 5<br />

void void *PrintHello(void *PrintHello(void *num) *num) {<br />

printf("\n%d: printf("\n%d: Hello Hello World!\n", World!\n", num); num);<br />

<strong>pthread</strong>_exit(NULL);<br />

<strong>pthread</strong>_exit(NULL);<br />

}<br />

Continua <br />

Aspetti preliminari dei thread POSIX 49


Esempio 3: thread join (2 <strong>di</strong> 3)<br />

int int main main (int (int argc, argc, char char *argv[]) *argv[]) {<br />

<strong>pthread</strong>_t <strong>pthread</strong>_t threads[NUM_THREADS];<br />

threads[NUM_THREADS];<br />

void void *status; *status;<br />

int int rc, rc, t; t;<br />

<strong>pthread</strong>_attr_t <strong>pthread</strong>_attr_t attr; attr;<br />

/* /* Inizializzazione Inizializzazione esplicita esplicita dello dello stato stato joinable joinable */ */<br />

<strong>pthread</strong>_attr_init(&attr);<br />

<strong>pthread</strong>_attr_init(&attr);<br />

<strong>pthread</strong>_attr_setdetachstate(&attr,<br />

<strong>pthread</strong>_attr_setdetachstate(&attr,<br />

PTHREAD_CREATE_JOINABLE);<br />

PTHREAD_CREATE_JOINABLE);<br />

for(t=0; for(t=0; t


Esempio 3: thread join (3 <strong>di</strong> 3)<br />

for(t=0; for(t=0; t


Sincronizzazione tra thread<br />

Attraverso variabili globali<br />

con<strong>di</strong>vise tra thread<br />

meccanismi <strong>di</strong> protezione<br />

Compito del programmatore<br />

corretto utilizzo delle funzioni <strong>di</strong><br />

sincronizzazione<br />

Meccanismi forniti dalla libreria<br />

semafori <strong>di</strong> mutua esclusione<br />

variabili con<strong>di</strong>tion<br />

semafori generali<br />

Aspetti preliminari dei thread POSIX 52


Semafori


Cosa sono i semafori?<br />

I semafori sono primitive fornite dal<br />

sistema operativo per permettere la<br />

sincronizzazione tra processi e/o<br />

thread.<br />

Aspetti preliminari dei thread POSIX 54


Operazioni sui semafori<br />

In genere sono tre le operazioni che vengono<br />

eseguite da un processo su<br />

un semaforo:<br />

Create: creazione <strong>di</strong> un semaforo.<br />

Wait: attesa su <strong>di</strong> un semaforo dove si verifica il<br />

valore del semaforo<br />

while(sem_value


Semafori <strong>di</strong> mutua esclusione


Cosa sono i mutex? (1 <strong>di</strong> 2)<br />

Una variabile mutex è una variabile<br />

che serve per la protezione delle<br />

sezioni critiche:<br />

variabili con<strong>di</strong>vise mo<strong>di</strong>ficate da più<br />

thread<br />

solo un thread alla volta può accedere ad<br />

una risorsa protetta da un mutex<br />

Il mutex è un semaforo binario cioè il<br />

valore può essere 0 (occupato) oppure<br />

1 (libero)<br />

Aspetti preliminari dei thread POSIX 57


Cosa sono i mutex? (2 <strong>di</strong> 2)<br />

Pensiamo ai mutex come a delle<br />

serrature:<br />

il primo thread che ha accesso alla coda<br />

dei lavori lascia fuori gli altri thread fino a<br />

che non ha portato a termine il suo<br />

compito.<br />

I threads piazzano un mutex nelle<br />

sezioni <strong>di</strong> co<strong>di</strong>ce nelle quali vengono<br />

con<strong>di</strong>visi i dati.<br />

Aspetti preliminari dei thread POSIX 58


Garantire la Mutua Esclusione (1<br />

<strong>di</strong> 2)<br />

Due thread devono decrementare il valore <strong>di</strong><br />

una variabile globale data se questa è<br />

maggiore <strong>di</strong> zero<br />

data = 1<br />

THREAD1<br />

THREAD2<br />

if(data>0)<br />

if(data>0)<br />

data --; data --;<br />

Aspetti preliminari dei thread POSIX 59


Garantire la Mutua Esclusione (2<br />

<strong>di</strong> 2)<br />

A seconda del tempo <strong>di</strong> esecuzione dei due thread, la<br />

variabile data assume valori <strong>di</strong>versi.<br />

Data THREAD1 THREAD2<br />

1 if(data>0)<br />

1 data --;<br />

0 if(data>0)<br />

0 data --;<br />

0 = valore finale <strong>di</strong> data<br />

--------------------------------------------------------<br />

1 if(data>0)<br />

1 if(data>0)<br />

1 data --;<br />

0 data --;<br />

-1 = valore finale <strong>di</strong> data<br />

Aspetti preliminari dei thread POSIX 60


Uso dei mutex<br />

Creare e inizializzare una variabile mutex<br />

Più thread tentano <strong>di</strong> accedere alla risorsa<br />

invocando l’operazione <strong>di</strong> lock<br />

Un solo thread riesce ad acquisire il mutex<br />

mentre gli altri si bloccano<br />

Il thread che ha acquisito il mutex manipola<br />

la risorsa<br />

Lo stesso thread la rilascia<br />

invocando la unlock<br />

Un altro thread acquisisce il mutex e così via<br />

Distruzione della variabile mutex<br />

Aspetti preliminari dei thread POSIX 61


Creazione mutex<br />

<br />

Per creare un mutex è necessario usare<br />

una variabile <strong>di</strong> tipo <strong>pthread</strong>_mutex_t<br />

contenuta nella libreria <strong>pthread</strong><br />

<strong>pthread</strong>_mutex_t è una struttura che<br />

contiene:<br />

Nome del mutex<br />

Proprietario<br />

Contatore<br />

Struttura associata al mutex<br />

<br />

<br />

La coda dei processi sospesi in attesa che mutex sia<br />

libero.<br />

… e simili<br />

Aspetti preliminari dei thread POSIX 62


Inizializzazione mutex<br />

statica<br />

contestuale alla <strong>di</strong>chiarazione<br />

<strong>di</strong>namica<br />

attraverso<br />

<strong>pthread</strong>_mutex_t mutex;<br />

<strong>pthread</strong>_mutex_init (&mutex, NULL);<br />

Aspetti preliminari dei thread POSIX 63


Inizializzazione statica<br />

<br />

Per il tipo <strong>di</strong> dato <strong>pthread</strong>_mutex_t, è definita la<br />

macro <strong>di</strong> inizializzazione<br />

PTHREAD_MUTEX_INITIALIZER<br />

<br />

Il mutex è un tipo definito "ad hoc" per gestire la<br />

mutua esclusione quin<strong>di</strong> il valore iniziale può<br />

essergli assegnato anche in modo statico me<strong>di</strong>ante<br />

questa macro.<br />

/* /* Variabili globali */ */<br />

<strong>pthread</strong>_mutex_t amutex = PTHREAD_MUTEX_INITIALIZER;<br />

Aspetti preliminari dei thread POSIX 64


Inizializzazione <strong>di</strong>namica<br />

<strong>pthread</strong>_mutex_t mutex;<br />

int int <strong>pthread</strong>_mutex_init( <strong>pthread</strong>_mutex_t *mutex, const<br />

<strong>pthread</strong>_mutexattr_t *mattr )<br />

<br />

<br />

<br />

<strong>pthread</strong>_mutex_t *mutex<br />

puntatore al mutex da inizializzare<br />

<strong>pthread</strong>_mutexattr_t *mattr<br />

attributi del mutex da inizializzare<br />

se NULL usa valori default<br />

Valore <strong>di</strong> ritorno<br />

sempre il valore 0<br />

Aspetti preliminari dei thread POSIX 65


Interfacce<br />

Su mutex sono possibili solo due<br />

operazioni: locking e unlocking<br />

(equivalenti a <strong>wait</strong> e signal sui<br />

semafori)<br />

Aspetti preliminari dei thread POSIX 66


Interfaccia: Lock<br />

Ogni thread, prima <strong>di</strong> accedere ai dati<br />

con<strong>di</strong>visi, deve effettuare la lock su una<br />

stessa variabile mutex.<br />

Blocca l’accesso da parte <strong>di</strong> altri thread.<br />

Se più thread eseguono l’operazione <strong>di</strong> lock<br />

su una stessa variabile mutex, solo uno dei<br />

thread termina la lock e prosegue<br />

l’esecuzione, gli altri rimangono bloccati<br />

nella lock. In tal modo, il processo che<br />

continua l’esecuzione può accedere ai dati<br />

(protetti me<strong>di</strong>ante la mutex).<br />

Aspetti preliminari dei thread POSIX 67


Operazioni: lock e trylock<br />

lock<br />

bloccante (standard)<br />

trylock<br />

non bloccante (utile per evitare deadlock)<br />

è come la lock() ma se si accorge che il mutex è<br />

già in possesso <strong>di</strong> un altro thread (e quin<strong>di</strong> si<br />

rimarrebbe bloccati) restituisce imme<strong>di</strong>atamente<br />

il controllo al chiamante con risultato EBUSY<br />

Una situazione <strong>di</strong> deadlock si verifica quando uno o più thread sono<br />

bloccati aspettando un evento che non si verificherà mai.<br />

Aspetti preliminari dei thread POSIX 68


lock<br />

int int <strong>pthread</strong>_mutex_lock( <strong>pthread</strong>_mutex_t *mutex )<br />

<strong>pthread</strong>_mutex_t *mutex<br />

puntatore al mutex da bloccare<br />

Valore <strong>di</strong> ritorno<br />

0 in caso <strong>di</strong> successo<br />

<strong>di</strong>verso da 0 altrimenti<br />

Aspetti preliminari dei thread POSIX 69


trylock<br />

int int <strong>pthread</strong>_mutex_trylock( <strong>pthread</strong>_mutex_t *mutex )<br />

<br />

<br />

<strong>pthread</strong>_mutex_t *mutex<br />

puntatore al mutex da bloccare<br />

Valore <strong>di</strong> ritorno<br />

0 in caso <strong>di</strong> successo e si ottenga la proprietà<br />

della mutex<br />

EBUSY se il mutex è occupato<br />

Aspetti preliminari dei thread POSIX 70


Interfaccia: Unlock<br />

Libera la variabile mutex.<br />

Un altro thread che ha<br />

precedentemente eseguito la lock<br />

della mutex potrà allora terminare la<br />

lock ed accedere a sua volta ai dati.<br />

Aspetti preliminari dei thread POSIX 71


unlock<br />

int int <strong>pthread</strong>_mutex_unlock( <strong>pthread</strong>_mutex_t *mutex )<br />

<strong>pthread</strong>_mutex_t *mutex<br />

puntatore al mutex da sbloccare<br />

Valore <strong>di</strong> ritorno<br />

0 in caso <strong>di</strong> successo<br />

Aspetti preliminari dei thread POSIX 72


destroy<br />

int int <strong>pthread</strong>_mutex_destroy( <strong>pthread</strong>_mutex_t *mutex )<br />

Elimina il mutex<br />

<strong>pthread</strong>_mutex_t *mutex<br />

puntatore al mutex da <strong>di</strong>struggere<br />

Valore <strong>di</strong> ritorno<br />

0 in caso <strong>di</strong> successo<br />

EBUSY se il mutex è occupato<br />

Aspetti preliminari dei thread POSIX 73


Esempio 4: uso dei mutex (1 <strong>di</strong> 2)<br />

#include #include <br />

<br />

int int a=1, a=1, b=1; b=1;<br />

<strong>pthread</strong>_mutex_t <strong>pthread</strong>_mutex_t m = PTHREAD_MUTEX_INITIALIZER;<br />

PTHREAD_MUTEX_INITIALIZER;<br />

void* void* thread1(void thread1(void *arg) *arg) {<br />

<strong>pthread</strong>_mutex_lock(&m);<br />

<strong>pthread</strong>_mutex_lock(&m);<br />

printf(“Primo printf(“Primo thread thread (parametro: (parametro: %d)\n", %d)\n", *(int*)arg);<br />

*(int*)arg);<br />

a++; a++; b++; b++;<br />

<strong>pthread</strong>_mutex_unlock(&m);<br />

<strong>pthread</strong>_mutex_unlock(&m);<br />

}<br />

}<br />

void* void* thread2(void thread2(void *arg) *arg) {<br />

<strong>pthread</strong>_mutex_lock(&m);<br />

<strong>pthread</strong>_mutex_lock(&m);<br />

printf(“Secondo<br />

printf(“Secondo<br />

thread<br />

thread<br />

(parametro:<br />

(parametro:<br />

%d)\n",<br />

%d)\n",<br />

*(int*)arg);<br />

*(int*)arg);<br />

b=b*2; b=b*2; a=a*2; a=a*2;<br />

<strong>pthread</strong>_mutex_unlock(&m);<br />

<strong>pthread</strong>_mutex_unlock(&m);<br />

} Continua<br />

Aspetti preliminari dei thread POSIX 74


Esempio 4: uso dei mutex (2 <strong>di</strong> 2)<br />

main() main() {<br />

<strong>pthread</strong>_t <strong>pthread</strong>_t threa<strong>di</strong>d1, threa<strong>di</strong>d1, threa<strong>di</strong>d2;<br />

threa<strong>di</strong>d2;<br />

int int i = 1, 1, j=2; j=2;<br />

<strong>pthread</strong>_create(&threa<strong>di</strong>d1, <strong>pthread</strong>_create(&threa<strong>di</strong>d1, NULL, NULL, thread1, thread1, (void (void *)&i); *)&i);<br />

<strong>pthread</strong>_create(&threa<strong>di</strong>d2, <strong>pthread</strong>_create(&threa<strong>di</strong>d2, NULL, NULL, thread2, thread2, (void (void *)&j); *)&j);<br />

<strong>pthread</strong>_join(threa<strong>di</strong>d1, <strong>pthread</strong>_join(threa<strong>di</strong>d1, NULL); NULL);<br />

<strong>pthread</strong>_join(threa<strong>di</strong>d2, <strong>pthread</strong>_join(threa<strong>di</strong>d2, NULL); NULL);<br />

printf("Valori<br />

printf("Valori<br />

finali:<br />

finali:<br />

a=%d<br />

a=%d<br />

b=%d\n",<br />

b=%d\n",<br />

a,<br />

a,<br />

b);<br />

b);<br />

}<br />

Tratto con mo<strong>di</strong>fiche da:<br />

http://www.univ.trieste.it/~mumolo/posix2.p<br />

df<br />

Aspetti preliminari dei thread POSIX 75


Esempio 5: inizializzazione <strong>di</strong>namica<br />

(1 <strong>di</strong> 2)<br />

#include #include <br />

<br />

int int a=1, a=1, b=1; b=1;<br />

<strong>pthread</strong>_mutex_t <strong>pthread</strong>_mutex_t m; m;<br />

void* void* thread1(void thread1(void *arg) *arg) {<br />

<strong>pthread</strong>_mutex_lock(&m);<br />

<strong>pthread</strong>_mutex_lock(&m);<br />

printf(“Primo printf(“Primo thread thread (parametro: (parametro: %d)\n", %d)\n", *(int*)arg);<br />

*(int*)arg);<br />

a++; a++; b++; b++;<br />

<strong>pthread</strong>_mutex_unlock(&m);<br />

<strong>pthread</strong>_mutex_unlock(&m);<br />

}<br />

}<br />

void* void* thread2(void thread2(void *arg) *arg) {<br />

<strong>pthread</strong>_mutex_lock(&m);<br />

<strong>pthread</strong>_mutex_lock(&m);<br />

printf(“Secondo<br />

printf(“Secondo<br />

thread<br />

thread<br />

(parametro:<br />

(parametro:<br />

%d)\n",<br />

%d)\n",<br />

*(int*)arg);<br />

*(int*)arg);<br />

b=b*2; b=b*2; a=a*2; a=a*2;<br />

<strong>pthread</strong>_mutex_unlock(&m);<br />

<strong>pthread</strong>_mutex_unlock(&m);<br />

} Continua<br />

Aspetti preliminari dei thread POSIX 76


Esempio 5: inizializzazione <strong>di</strong>namica<br />

(2 <strong>di</strong> 2)<br />

main() main() {<br />

<strong>pthread</strong>_t <strong>pthread</strong>_t threa<strong>di</strong>d1, threa<strong>di</strong>d1, threa<strong>di</strong>d2;<br />

threa<strong>di</strong>d2;<br />

int int i = 1, 1, j=2; j=2;<br />

<strong>pthread</strong>_mutex_init(&m, <strong>pthread</strong>_mutex_init(&m, NULL); NULL);<br />

<strong>pthread</strong>_create(&threa<strong>di</strong>d1, <strong>pthread</strong>_create(&threa<strong>di</strong>d1, NULL, NULL, thread1, thread1, (void (void *)&i); *)&i);<br />

<strong>pthread</strong>_create(&threa<strong>di</strong>d2,<br />

<strong>pthread</strong>_create(&threa<strong>di</strong>d2,<br />

NULL,<br />

NULL,<br />

thread2,<br />

thread2,<br />

(void<br />

(void<br />

*)&j);<br />

*)&j);<br />

<strong>pthread</strong>_join(threa<strong>di</strong>d1, <strong>pthread</strong>_join(threa<strong>di</strong>d1, NULL); NULL);<br />

<strong>pthread</strong>_join(threa<strong>di</strong>d2, <strong>pthread</strong>_join(threa<strong>di</strong>d2, NULL); NULL);<br />

printf("Valori printf("Valori finali: finali: a=%d a=%d b=%d\n", b=%d\n", a, a, b); b);<br />

<strong>pthread</strong>_mutex_destroy(&m);<br />

<strong>pthread</strong>_mutex_destroy(&m);<br />

}<br />

Aspetti preliminari dei thread POSIX 77


Esempio 6 (1 <strong>di</strong> 3)<br />

/* /* esempio utilizzo dei dei Mutex */ */<br />

#include <br />

#include <br />

<strong>pthread</strong>_mutex_t mymutex;<br />

void *body(void *arg){<br />

int int i,j;<br />

for for (j=0; j


Esempio 6 (2 <strong>di</strong> 3)<br />

int int main(){<br />

<strong>pthread</strong>_t t1,t2,t3;<br />

<strong>pthread</strong>_attr_t myattr;<br />

int int err;<br />

<strong>pthread</strong>_mutexattr_t mymutexattr;<br />

<strong>pthread</strong>_mutexattr_init(&mymutexattr);<br />

<strong>pthread</strong>_mutex_init(&mymutex, &mymutexattr);<br />

<strong>pthread</strong>_mutexattr_destroy(&mymutexattr);<br />

<strong>pthread</strong>_attr_init(&myattr);<br />

…<br />

Continua<br />

<br />

Aspetti preliminari dei thread POSIX 79


Esempio 6 (3 <strong>di</strong> 3)<br />

err err = <strong>pthread</strong>_create(&t1, &myattr, body, body, (void (void *)".");<br />

err err = <strong>pthread</strong>_create(&t2, &myattr, body, body, (void (void *)"#");<br />

err err = <strong>pthread</strong>_create(&t3, &myattr, body, body, (void (void *)"o");<br />

<strong>pthread</strong>_attr_destroy(&myattr);<br />

}<br />

<strong>pthread</strong>_join(t1, NULL);<br />

<strong>pthread</strong>_join(t2, NULL);<br />

<strong>pthread</strong>_join(t3, NULL);<br />

printf("\n");<br />

return 0; 0;<br />

Aspetti preliminari dei thread POSIX 80


Esercizio 3<br />

<strong>pthread</strong>s-3a-mutex.c<br />

analizzare l'output<br />

mo<strong>di</strong>ficare in modo da ottenere un<br />

funzionamento corretto<br />

<strong>pthread</strong>s-3b-mutex.c<br />

soluzione dell'esercizio precedente<br />

Aspetti preliminari dei thread POSIX 81


<strong>pthread</strong>s-3a-mutex.c<br />

#include <br />

#include <br />

#define NUM_THREADS 40<br />

int shared = 0;<br />

void *thread_main(void* arg){<br />

int i,k;<br />

for (i=0; i


Variabili con<strong>di</strong>tion


Con<strong>di</strong>tion vs Semafori<br />

Le variabili con<strong>di</strong>tion sono molto <strong>di</strong>verse dai<br />

semafori <strong>di</strong> sincronizzazione, anche se<br />

semanticamente fanno la stessa cosa<br />

Le primitive delle con<strong>di</strong>tion si preoccupano <strong>di</strong><br />

rilasciare la mutua esclusione prima <strong>di</strong><br />

bloccarsi e ed riacquisirla dopo essere state<br />

sbloccate<br />

I semafori generali, invece, prescindono dalla<br />

presenza <strong>di</strong> altri meccanismi<br />

Aspetti preliminari dei thread POSIX 84


Cosa sono le variabili con<strong>di</strong>tion<br />

Strumento <strong>di</strong> sincronizzazione: consente<br />

la sospensione dei thread in attesa che sia<br />

sod<strong>di</strong>sfatta una con<strong>di</strong>zione logica.<br />

Una con<strong>di</strong>tion variable è utilizzata per<br />

sospendere l'esecuzione <strong>di</strong> un thread in<br />

attesa che si verifichi un certo evento.<br />

Ad ogni con<strong>di</strong>tion viene associata una coda<br />

per la sospensione dei thread.<br />

La variabile con<strong>di</strong>zione non ha uno stato,<br />

rappresenta solo una coda <strong>di</strong> thread.<br />

Aspetti preliminari dei thread POSIX 85


Variabili con<strong>di</strong>tion<br />

Attraverso le variabili con<strong>di</strong>tion è<br />

possibile implementare con<strong>di</strong>zioni più<br />

complesse che i thread devono<br />

sod<strong>di</strong>sfare per essere eseguiti.<br />

Linux garantisce che i thread bloccati<br />

su una con<strong>di</strong>zione vengano sbloccati<br />

quando essa cambia.<br />

Aspetti preliminari dei thread POSIX 86


Mutua esclusione<br />

Una variabile con<strong>di</strong>zione non fornisce<br />

la mutua esclusione.<br />

C'è bisogno <strong>di</strong> un mutex per poter<br />

sincronizzare l'accesso ai dati.<br />

Aspetti preliminari dei thread POSIX 87


Sincronizzazione<br />

Una variabile con<strong>di</strong>tion è sempre associata<br />

ad un mutex<br />

un thread ottiene il mutex e testa il pre<strong>di</strong>cato<br />

se il pre<strong>di</strong>cato è verificato allora il thread<br />

esegue le sue operazioni e rilascia il mutex<br />

se il pre<strong>di</strong>cato non è verificato, in modo<br />

atomico<br />

il mutex viene rilasciato (implicitamente)<br />

il thread si blocca sulla variabile con<strong>di</strong>tion<br />

un thread bloccato riacquisisce il mutex nel<br />

momento in cui viene svegliato da un altro<br />

thread<br />

Aspetti preliminari dei thread POSIX 88


Creazione con<strong>di</strong>tion<br />

Oggetti <strong>di</strong> sincronizzazione su cui un<br />

processo si può bloccare in attesa<br />

associate ad una con<strong>di</strong>zione logica<br />

arbitraria<br />

generalizzazione dei semafori<br />

nuovo tipo <strong>pthread</strong>_cond_t<br />

attributi variabili con<strong>di</strong>zione <strong>di</strong> tipo<br />

<strong>pthread</strong>_condattr_t<br />

Aspetti preliminari dei thread POSIX 89


Inizializzazione statica<br />

<strong>pthread</strong>_cond_t cond = PTHREAD_COND_INITIALIZER;<br />

• Per il tipo <strong>di</strong> dato <strong>pthread</strong>_cond_t, è definita<br />

la macro <strong>di</strong> inizializzazione<br />

PTHREAD_COND_INITIALIZER<br />

Aspetti preliminari dei thread POSIX 90


Inizializzazione <strong>di</strong>namica<br />

int int <strong>pthread</strong>_cond_init( <strong>pthread</strong>_cond_t *cond,<br />

<strong>pthread</strong>_condattr_t *cond_attr )<br />

<br />

<br />

<strong>pthread</strong>_cond_t *cond<br />

puntatore ad un’istanza <strong>di</strong> con<strong>di</strong>tion che<br />

rappresenta la con<strong>di</strong>zione <strong>di</strong> sincronizzazione<br />

<strong>pthread</strong>_condattr_t *cond_attr<br />

punta a una struttura che contiene gli attributi<br />

della con<strong>di</strong>zione<br />

se NULL usa valori <strong>di</strong> default<br />

Aspetti preliminari dei thread POSIX 91


Distruzione variabili con<strong>di</strong>tion<br />

int int <strong>pthread</strong>_cond_destroy( <strong>pthread</strong>_cond_t *cond )<br />

Dealloca tutte le risorse allocate per gestire la<br />

variabile con<strong>di</strong>zione specificata<br />

Non devono esistere thread in attesa della<br />

con<strong>di</strong>zione<br />

<strong>pthread</strong>_cond_t *cond<br />

puntatore ad un’istanza <strong>di</strong> con<strong>di</strong>tion da <strong>di</strong>struggere<br />

Valore <strong>di</strong> ritorno<br />

0 in caso <strong>di</strong> successo oppure un co<strong>di</strong>ce d’errore ≠0<br />

Aspetti preliminari dei thread POSIX 92


Interfacce<br />

Operazioni fondamentali:<br />

<strong>wait</strong> (sospensione)<br />

signal ( risveglio)<br />

Aspetti preliminari dei thread POSIX 93


Interfaccia <strong>wait</strong><br />

La <strong>wait</strong> serve per sincronizzarsi con una certa<br />

con<strong>di</strong>zione all'interno <strong>di</strong> un blocco <strong>di</strong> dati con<strong>di</strong>visi e<br />

protetti da un mutex<br />

La presenza del mutex fra i parametri garantisce<br />

che, al momento del bloccaggio, esso venga<br />

liberato, eliminando a monte possibili errori <strong>di</strong><br />

programmazione che potrebbero condurre a<br />

con<strong>di</strong>zioni <strong>di</strong> deadlock.<br />

Se la <strong>wait</strong> ritorna in modo regolare, è garantito che<br />

la mutua esclusione, sul semaforo mutex passatole,<br />

sia stata nuovamente acquisita.<br />

Aspetti preliminari dei thread POSIX 94


<strong>wait</strong><br />

int int <strong>pthread</strong>_cond_<strong>wait</strong>( <strong>pthread</strong>_cond_t *cond,<br />

<strong>pthread</strong>_mutex_t *mutex )<br />

<br />

<br />

<br />

<strong>pthread</strong>_cond_t *cond<br />

puntatore ad un’istanza <strong>di</strong> con<strong>di</strong>tion che<br />

rappresenta la con<strong>di</strong>zione <strong>di</strong> sincronizzazione<br />

puntatore all’oggetto con<strong>di</strong>zione su cui bloccarsi<br />

<strong>pthread</strong>_mutex_t *mutex<br />

l'in<strong>di</strong>rizzo <strong>di</strong> un semaforo <strong>di</strong> mutua esclusione<br />

necessario alla corretta consistenza dei dati<br />

Valore <strong>di</strong> ritorno<br />

sempre 0<br />

Aspetti preliminari dei thread POSIX 95


Interfaccia signal<br />

La signal non si preoccupa <strong>di</strong> liberare la<br />

mutua esclusione, infatti, fra i suoi parametri<br />

non c'è il mutex<br />

Il mutex deve essere rilasciato<br />

esplicitamente, altrimenti si potrebbe<br />

produrre una con<strong>di</strong>zione <strong>di</strong> deadlock.<br />

Due varianti<br />

Standard: sblocca un solo thread bloccato<br />

Broadcast: sblocca tutti i thread bloccati<br />

Aspetti preliminari dei thread POSIX 96


signal<br />

int int <strong>pthread</strong>_cond_signal ( <strong>pthread</strong>_cond_t *cond)<br />

Se esistono thread sospesi nella coda associata a<br />

cond, viene risvegliato il primo.<br />

Se non vi sono thread sospesi sulla con<strong>di</strong>zione, la<br />

signal non ha effetto.<br />

<strong>pthread</strong>_cond_t *cond<br />

puntatore all’oggetto con<strong>di</strong>zione<br />

Valore <strong>di</strong> ritorno<br />

sempre 0<br />

Aspetti preliminari dei thread POSIX 97


oadcast<br />

int int <strong>pthread</strong>_cond_broadcast ( <strong>pthread</strong>_cond_t *cond )<br />

Se esistono thread sospesi nella coda<br />

associata a cond, vengono svegliati tutti<br />

altrimenti nessun effetto<br />

<strong>pthread</strong>_cond_t *cond<br />

puntatore all’oggetto con<strong>di</strong>zione<br />

Valore <strong>di</strong> ritorno<br />

sempre 0<br />

Aspetti preliminari dei thread POSIX 98


Valutazione con<strong>di</strong>zione<br />

Il thread svegliato deve rivalutare la con<strong>di</strong>zione<br />

l’altro thread potrebbe non aver testato la<br />

con<strong>di</strong>zione<br />

la con<strong>di</strong>zione potrebbe essere cambiata nel<br />

frattempo<br />

possono verificarsi wakeup “spuri”<br />

<strong>pthread</strong>_mutex_lock(&mutex);<br />

while(!con<strong>di</strong>tion_to_hold)<br />

ptread_cond_<strong>wait</strong>(&cond, &mutex);<br />

computation();<br />

<strong>pthread</strong>_mutex_unlock(&mutex);<br />

Aspetti preliminari dei thread POSIX 99


Stato della coda<br />

Non è prevista una funzione per<br />

verificare lo stato della coda associata<br />

a una con<strong>di</strong>zione.<br />

Aspetti preliminari dei thread POSIX 100


Esempio <strong>di</strong> utilizzo (1 <strong>di</strong> 2)<br />

Risorsa che può essere usata<br />

contemporaneamente da MAX thread.<br />

con<strong>di</strong>tion PIENO per la sospensione dei thread<br />

M mutex associato a pieno<br />

N_int numero <strong>di</strong> thread che stanno utilizzando la<br />

risorsa<br />

#define MAX 100<br />

/*variabili globali*/<br />

int N_in=0 /*numero thread che stanno utilizzando la risorsa*/<br />

<strong>pthread</strong>_cond_t PIENO;<br />

<strong>pthread</strong>_ mutex M;/*mutex associato alla cond. PIENO*/<br />

Aspetti preliminari dei thread POSIX 101


Esempio <strong>di</strong> utilizzo (2 <strong>di</strong> 2)<br />

void co<strong>di</strong>ce_thread() {<br />

/*fase <strong>di</strong> entrata*/<br />

<strong>pthread</strong>_mutex_lock(&M);<br />

/* controlla la con<strong>di</strong>zione <strong>di</strong> ingresso*/<br />

if(N_in == MAX)<br />

<strong>pthread</strong>_cond_<strong>wait</strong>(&PIENO,&M);<br />

/*aggiorna lo stato della risorsa */<br />

N_in ++;<br />

<strong>pthread</strong>_mutex_unlock(&M);<br />

<br />

/*fase <strong>di</strong> uscita*/<br />

<strong>pthread</strong>_mutex_lock(&M);<br />

/*aggiorna lo stato della risorsa */<br />

N_in --;<br />

<strong>pthread</strong>_cond_signal(&PIENO);<br />

<strong>pthread</strong>_mutex_unlock(&M);<br />

}<br />

Aspetti preliminari dei thread POSIX 102


Esempio 8 (1 <strong>di</strong> 4)<br />

#include #include <br />

<br />

#include #include <br />

<br />

#include #include <br />

<br />

/* /* mutex mutex */ */<br />

<strong>pthread</strong>_mutex_t <strong>pthread</strong>_mutex_t con<strong>di</strong>tion_mutex con<strong>di</strong>tion_mutex = PTHREAD_MUTEX_INITIALIZER;<br />

PTHREAD_MUTEX_INITIALIZER;<br />

/* /* con<strong>di</strong>tion con<strong>di</strong>tion variable*/<br />

variable*/<br />

<strong>pthread</strong>_cond_t<br />

<strong>pthread</strong>_cond_t<br />

con<strong>di</strong>tion_cond<br />

con<strong>di</strong>tion_cond<br />

=<br />

=<br />

PTHREAD_COND_INITIALIZER;<br />

PTHREAD_COND_INITIALIZER;<br />

Continua<br />

<br />

Aspetti preliminari dei thread POSIX 103


Esempio 8 (2 <strong>di</strong> 4)<br />

void void thread1_func(void thread1_func(void *ptr) *ptr) {<br />

printf("Avvio printf("Avvio dell’esecuzione dell’esecuzione del del %s.\n",(char %s.\n",(char *)ptr); *)ptr);<br />

sleep(2); sleep(2); /* /* pausa pausa <strong>di</strong> <strong>di</strong> 2 secon<strong>di</strong> secon<strong>di</strong> */ */<br />

printf("<strong>Thread</strong> printf("<strong>Thread</strong> 1 in in procinto procinto <strong>di</strong> <strong>di</strong> entrare entrare nella nella sezione sezione critica.\n");<br />

critica.\n");<br />

<strong>pthread</strong>_mutex_lock(&con<strong>di</strong>tion_mutex);<br />

<strong>pthread</strong>_mutex_lock(&con<strong>di</strong>tion_mutex);<br />

printf("<strong>Thread</strong> printf("<strong>Thread</strong> 1 nella nella sezione sezione critica.\n");<br />

critica.\n");<br />

printf("<strong>Thread</strong><br />

printf("<strong>Thread</strong><br />

1<br />

1<br />

si<br />

si<br />

sospende<br />

sospende<br />

sulla<br />

sulla<br />

con<strong>di</strong>tion<br />

con<strong>di</strong>tion<br />

variable.\n");<br />

variable.\n");<br />

<strong>pthread</strong>_cond_<strong>wait</strong>(&con<strong>di</strong>tion_cond, <strong>pthread</strong>_cond_<strong>wait</strong>(&con<strong>di</strong>tion_cond, &con<strong>di</strong>tion_mutex);<br />

&con<strong>di</strong>tion_mutex);<br />

printf("<strong>Thread</strong> printf("<strong>Thread</strong> 1 riprende riprende l’esecuzione.\n");<br />

l’esecuzione.\n");<br />

printf("<strong>Thread</strong> printf("<strong>Thread</strong> 1 in in procinto procinto <strong>di</strong> <strong>di</strong> uscire uscire dalla dalla sezione sezione critica.\n");<br />

critica.\n");<br />

<strong>pthread</strong>_mutex_unlock(&con<strong>di</strong>tion_mutex);<br />

<strong>pthread</strong>_mutex_unlock(&con<strong>di</strong>tion_mutex);<br />

printf("<strong>Thread</strong> printf("<strong>Thread</strong> 1 in in procinto procinto <strong>di</strong> <strong>di</strong> terminare.\n");<br />

terminare.\n");<br />

}<br />

}<br />

Continua<br />

<br />

Aspetti preliminari dei thread POSIX 104


Esempio 8 (3 <strong>di</strong> 4)<br />

void void thread2_func(void thread2_func(void *ptr) *ptr) {<br />

printf("Avvio printf("Avvio dell’esecuzione dell’esecuzione del del %s.\n",(char %s.\n",(char *)ptr); *)ptr);<br />

sleep(5); sleep(5); /* /* pausa pausa <strong>di</strong> <strong>di</strong> 5 secon<strong>di</strong> secon<strong>di</strong> */ */<br />

printf("<strong>Thread</strong> printf("<strong>Thread</strong> 2 in in procinto procinto <strong>di</strong> <strong>di</strong> entrare entrare nella nella sezione sezione critica.\n");<br />

critica.\n");<br />

<strong>pthread</strong>_mutex_lock(&con<strong>di</strong>tion_mutex);<br />

<strong>pthread</strong>_mutex_lock(&con<strong>di</strong>tion_mutex);<br />

printf("<strong>Thread</strong> printf("<strong>Thread</strong> 2 nella nella sezione sezione critica.\n");<br />

critica.\n");<br />

printf("<strong>Thread</strong><br />

printf("<strong>Thread</strong><br />

2<br />

2<br />

segnala<br />

segnala<br />

l’evento<br />

l’evento<br />

della<br />

della<br />

con<strong>di</strong>tion<br />

con<strong>di</strong>tion<br />

variable.\n");<br />

variable.\n");<br />

<strong>pthread</strong>_cond_signal(&con<strong>di</strong>tion_cond);<br />

<strong>pthread</strong>_cond_signal(&con<strong>di</strong>tion_cond);<br />

printf("<strong>Thread</strong> printf("<strong>Thread</strong> 2 in in procinto procinto <strong>di</strong> <strong>di</strong> uscire uscire dalla dalla sezione sezione critica.\n");<br />

critica.\n");<br />

<strong>pthread</strong>_mutex_unlock(&con<strong>di</strong>tion_mutex);<br />

<strong>pthread</strong>_mutex_unlock(&con<strong>di</strong>tion_mutex);<br />

}<br />

printf("<strong>Thread</strong> printf("<strong>Thread</strong> 2 in in procinto procinto <strong>di</strong> <strong>di</strong> terminare.\n");<br />

terminare.\n");<br />

Continua<br />

<br />

Aspetti preliminari dei thread POSIX 105


Esempio 8 (4 <strong>di</strong> 4)<br />

main() main() {<br />

<strong>pthread</strong>_t <strong>pthread</strong>_t thread1,thread2;<br />

thread1,thread2;<br />

char char *msg1="<strong>Thread</strong> *msg1="<strong>Thread</strong> 1"; 1";<br />

char char *msg2="<strong>Thread</strong> *msg2="<strong>Thread</strong> 2"; 2";<br />

if(<strong>pthread</strong>_create(&thread1,NULL,(void if(<strong>pthread</strong>_create(&thread1,NULL,(void *)&thread1_func,(void *)&thread1_func,(void *)msg1)!=0){<br />

*)msg1)!=0){<br />

perror("Errore perror("Errore nella nella creazione creazione del del primo primo thread.\n");<br />

thread.\n");<br />

exit(1); exit(1);<br />

}<br />

}<br />

if(<strong>pthread</strong>_create(&thread2,NULL,(void if(<strong>pthread</strong>_create(&thread2,NULL,(void *)&thread2_func,(void *)&thread2_func,(void *)msg2)!=0){<br />

*)msg2)!=0){<br />

perror("Errore perror("Errore nella nella creazione creazione del del secondo secondo thread.\n");<br />

thread.\n");<br />

exit(1); exit(1);<br />

}<br />

<strong>pthread</strong>_join(thread1,NULL);<br />

<strong>pthread</strong>_join(thread1,NULL);<br />

<strong>pthread</strong>_join(thread2,NULL);<br />

<strong>pthread</strong>_join(thread2,NULL);<br />

exit(0); exit(0);<br />

}<br />

Aspetti preliminari dei thread POSIX 106


Esempio 9: incremento contatore<br />

3)<br />

(1 <strong>di</strong><br />

void void *inc_count(void *inc_count(void *idp) *idp) {<br />

int int j,i; j,i; double double result=0.0; result=0.0; int int *my_id *my_id = idp; idp;<br />

for for (i=0; (i=0; i


Esempio 9: incremento contatore<br />

3)<br />

(2 <strong>di</strong><br />

void void *watch_count(void *watch_count(void *idp) *idp) {<br />

int int *my_id *my_id = idp; idp;<br />

printf("Starting printf("Starting watch_count(): watch_count(): thread thread %d\n", %d\n", *my_id); *my_id);<br />

<strong>pthread</strong>_mutex_lock(&count_mutex); <strong>pthread</strong>_mutex_lock(&count_mutex); /*Lock /*Lock mutex mutex and and <strong>wait</strong> <strong>wait</strong> for for signal. signal. */ */<br />

while while (count


Esempio 9: incremento contatore<br />

3)<br />

(3 <strong>di</strong><br />

int int main main (int (int argc, argc, char char *argv[]) *argv[]) {<br />

int int i, i, res; res;<br />

<strong>pthread</strong>_t <strong>pthread</strong>_t threads[3];<br />

threads[3];<br />

<strong>pthread</strong>_attr_t <strong>pthread</strong>_attr_t attr; attr;<br />

/* /* Initialize Initialize mutex mutex and and con<strong>di</strong>tion con<strong>di</strong>tion variable variable objects objects */ */<br />

<strong>pthread</strong>_mutex_init(&count_mutex, <strong>pthread</strong>_mutex_init(&count_mutex, NULL); NULL);<br />

<strong>pthread</strong>_cond_init <strong>pthread</strong>_cond_init (&count_threshold_cv, (&count_threshold_cv, NULL); NULL);<br />

/*<br />

/*<br />

Create<br />

Create<br />

threads<br />

threads<br />

and<br />

and<br />

<strong>wait</strong><br />

<strong>wait</strong><br />

for<br />

for<br />

all<br />

all<br />

threads<br />

threads<br />

to<br />

to<br />

complete<br />

complete<br />

*/<br />

*/<br />

…<br />

/* /* Clean Clean up up and and exit exit */ */<br />

<strong>pthread</strong>_attr_destroy(&attr);<br />

<strong>pthread</strong>_attr_destroy(&attr);<br />

<strong>pthread</strong>_mutex_destroy(&count_mutex);<br />

<strong>pthread</strong>_mutex_destroy(&count_mutex);<br />

<strong>pthread</strong>_cond_destroy(&count_threshold_cv);<br />

<strong>pthread</strong>_cond_destroy(&count_threshold_cv);<br />

<strong>pthread</strong>_exit(NULL);<br />

<strong>pthread</strong>_exit(NULL);<br />

}<br />

Aspetti preliminari dei thread POSIX 109


Esempio 10 (1 <strong>di</strong> 6)<br />

#include<br />

#include<br />

<br />

<br />

#include #include <br />

<br />

#include #include <br />

<br />

#include #include <br />

<br />

#include #include <br />

<br />

#include #include <br />

<br />

/* /* Numero Numero <strong>di</strong> <strong>di</strong> cicli cicli <strong>di</strong> <strong>di</strong> lettura/scrittura lettura/scrittura che che vengono vengono fatti fatti dai dai thread thread */ */<br />

#define #define CICLI CICLI 1<br />

/* /* Lunghezza Lunghezza del del buffer buffer */ */<br />

#define #define LUN LUN 20 20<br />

/* /* Numero Numero <strong>di</strong> <strong>di</strong> cicli cicli <strong>di</strong> <strong>di</strong> attesa attesa a vuoto vuoto <strong>di</strong> <strong>di</strong> uno uno scrittore scrittore */ */<br />

#define #define DELAY_WRITER DELAY_WRITER 200000 200000<br />

/* /* Numero Numero <strong>di</strong> <strong>di</strong> cicli cicli <strong>di</strong> <strong>di</strong> attesa attesa a vuoto vuoto <strong>di</strong> <strong>di</strong> uno uno scrittore scrittore */ */<br />

#define #define DELAY_READER DELAY_READER 2000000 2000000<br />

Aspetti preliminari dei thread POSIX 110


Esempio 10 (2 <strong>di</strong> 6)<br />

/*<br />

/*<br />

Memoria<br />

Memoria<br />

Con<strong>di</strong>visa<br />

Con<strong>di</strong>visa<br />

fra<br />

fra<br />

i<br />

i<br />

thread<br />

thread<br />

...<br />

...<br />

*/<br />

*/<br />

struct struct {<br />

/* /* Semaforo Semaforo <strong>di</strong> <strong>di</strong> mutua mutua esclusione esclusione */ */<br />

<strong>pthread</strong>_mutex_t <strong>pthread</strong>_mutex_t mutex; mutex;<br />

/* /* Variabile Variabile con<strong>di</strong>tion con<strong>di</strong>tion per per il il lettore lettore */ */<br />

<strong>pthread</strong>_cond_t <strong>pthread</strong>_cond_t lettore; lettore;<br />

/* /* Variabile Variabile con<strong>di</strong>tion con<strong>di</strong>tion per per gli gli scrittori scrittori */ */<br />

<strong>pthread</strong>_cond_t <strong>pthread</strong>_cond_t scrittori;<br />

scrittori;<br />

/* /* Buffer Buffer */ */<br />

char char scritta[LUN+1];<br />

scritta[LUN+1];<br />

/* /* Variabili Variabili per per la la gestione gestione del del buffer buffer */ */<br />

int int primo, primo, ultimo, ultimo, elementi;<br />

elementi;<br />

/* /* Numero Numero <strong>di</strong> <strong>di</strong> lettori lettori e scrittori scrittori bloccati bloccati */ */<br />

int int blockscri, blockscri, blocklet;<br />

blocklet;<br />

} shared shared = {PTHREAD_MUTEX_INITIALIZER,<br />

{PTHREAD_MUTEX_INITIALIZER,<br />

PTHREAD_COND_INITIALIZER,<br />

PTHREAD_COND_INITIALIZER,<br />

PTHREAD_COND_INITIALIZER};<br />

PTHREAD_COND_INITIALIZER};<br />

Aspetti preliminari dei thread POSIX 111


Esempio 10 (3 <strong>di</strong> 6)<br />

int<br />

int<br />

main(void){<br />

main(void){<br />

<strong>pthread</strong>_t <strong>pthread</strong>_t s1TID, s1TID, s2TID, s2TID, lTID; lTID;<br />

int int res, res, i; i;<br />

/* /* Inizializzo Inizializzo la la stringa stringa scritta scritta */ */<br />

for(i=0; for(i=0; i


Esempio 10 (4 <strong>di</strong> 6)<br />

res<br />

res<br />

=<br />

=<br />

<strong>pthread</strong>_create(&lTID,<br />

<strong>pthread</strong>_create(&lTID,<br />

NULL,<br />

NULL,<br />

lettore,<br />

lettore,<br />

NULL);<br />

NULL);<br />

if if (res (res != != 0) 0) printf("Errore printf("Errore nella nella creazione creazione del del primo primo thread\n");<br />

thread\n");<br />

res res = <strong>pthread</strong>_create(&s1TID, <strong>pthread</strong>_create(&s1TID, NULL, NULL, scrittore1, scrittore1, NULL); NULL);<br />

if if (res (res != != 0) 0) {<br />

printf("Errore printf("Errore nella nella creazione creazione del del secondo secondo thread\n");<br />

thread\n");<br />

<strong>pthread</strong>_kill(s1TID, <strong>pthread</strong>_kill(s1TID, SIGKILL);exit(-1);<br />

SIGKILL);exit(-1);<br />

}<br />

res res = <strong>pthread</strong>_create(&s2TID, <strong>pthread</strong>_create(&s2TID, NULL, NULL, scrittore2, scrittore2, NULL); NULL);<br />

if if (res (res != != 0) 0) {<br />

printf("Errore printf("Errore nella nella creazione creazione del del terzo terzo thread\n");<br />

thread\n");<br />

<strong>pthread</strong>_kill(lTID, <strong>pthread</strong>_kill(lTID, SIGKILL);<strong>pthread</strong>_kill(s1TID, SIGKILL);<strong>pthread</strong>_kill(s1TID, SIGKILL);<br />

SIGKILL);<br />

return return -1; -1;<br />

}<br />

/* /* Aspetto Aspetto che che i tre tre thread thread finiscano finiscano ... ... */ */<br />

<strong>pthread</strong>_join(s1TID, <strong>pthread</strong>_join(s1TID, NULL);<strong>pthread</strong>_join(s2TID, NULL);<strong>pthread</strong>_join(s2TID, NULL); NULL);<br />

<strong>pthread</strong>_join(lTID,<br />

<strong>pthread</strong>_join(lTID,<br />

NULL);<br />

NULL);<br />

printf("E' printf("E' finito finito l'esperimento l'esperimento ....\n");<br />

....\n");<br />

return return (0); (0);<br />

}<br />

Aspetti preliminari dei thread POSIX 113


Esempio 10 (5 <strong>di</strong> 6)<br />

void *scrittore1(void *in){<br />

void *scrittore1(void *in){<br />

int<br />

int<br />

i,<br />

i,<br />

j,<br />

j,<br />

k;<br />

k;<br />

for<br />

for<br />

(i=0;<br />

(i=0;<br />

i


Esempio 10 (6 <strong>di</strong> 6)<br />

void *lettore(void *in){<br />

void *lettore(void *in){<br />

int<br />

int<br />

i,<br />

i,<br />

k,<br />

k,<br />

j;<br />

j;<br />

char<br />

char<br />

local[LUN+1];<br />

local[LUN+1];<br />

local[LUN]<br />

local[LUN]<br />

=<br />

=<br />

0;<br />

0;<br />

for<br />

for<br />

(i=0;<br />

(i=0;<br />

i


Esercizio 4<br />

<strong>pthread</strong>s-4a-barrier.c<br />

mo<strong>di</strong>ficare in modo da ottenere la<br />

sincronizzazione desiderata<br />

tutti i thread si bloccano alla barriera<br />

aspettando l'arrivo <strong>di</strong> tutti gli altri<br />

tutti i thread proseguono l'esecuzione<br />

quando l'ultimo ha raggiunto la barriera<br />

suggerimento: usare una variabile<br />

con<strong>di</strong>tion<br />

<strong>pthread</strong>s-4b-barrier.c<br />

soluzione dell'esercizio precedente<br />

Aspetti preliminari dei thread POSIX 116


<strong>pthread</strong>s-4a-barrier.c<br />

(1 <strong>di</strong> 2)<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#define NUM_THREADS 4<br />

/* Some variables are needed here... */<br />

int n_threads; /* number of worker threads */<br />

/* Complete the function body */<br />

void barrier()<br />

{<br />

}<br />

void *parallel_elaboration(void * arg)<br />

{<br />

int delay = rand()%6;<br />

int i = *(int*)arg;<br />

printf("[<strong>Thread</strong> %d] Waiting for %d secs...\n",i,delay);<br />

sleep(delay);<br />

printf("[<strong>Thread</strong> %d] ...elaboration finished, <strong>wait</strong>ing for the other threads...\n",i);<br />

barrier();<br />

printf("[<strong>Thread</strong> %d] ...ok!\n",i);<br />

<strong>pthread</strong>_exit(NULL);<br />

}<br />

Continua <br />

Aspetti preliminari dei thread POSIX 117


<strong>pthread</strong>s-4a-barrier.c<br />

(2 <strong>di</strong> 2)<br />

int main(void)<br />

{<br />

<strong>pthread</strong>_t tids[NUM_THREADS];<br />

int params[NUM_THREADS];<br />

int i, rc;<br />

n_threads = NUM_THREADS;<br />

/* Some initialization goes here... */<br />

srand ( time(NULL) );<br />

printf("[Main] Starting...\n");<br />

for (i=0; i

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!