Thread: sincronizzazione Esercitazioni del 09 Ottobre 2009



Documenti analoghi
Programmazione concorrente

Thread: sincronizzazione Esercitazioni del 16 Ottobre 2009

I thread nel sistema operativo LINUX: Linuxthreads

Realizzazione di Politiche di Gestione delle Risorse: i Semafori Privati

Programmazione di concorrente - Deadlock

Sistemi Operativi L-A. Esercizi 14 Giugno Esercizio monitor

Java threads (2) Programmazione Concorrente

Lab. di Sistemi Operativi - Esercitazione n 9- -Thread-

3.2 Concorrenza, parallelismo e parallelismo reale

Linuxthreads: esercizio

Sistemi Operativi (M. Cesati)

Monitor pthreads. Esercizio

Architetture dei Calcolatori e Sistemi Operativi

Monitor. Introduzione. Struttura di un TDA Monitor

2. Spiegare brevemente qual è la funzione del compilatore e la sua importanza per il programmatore.

Esercizio 1 - nucleo e commutazione tra processi

Per scrivere una procedura che non deve restituire nessun valore e deve solo contenere le informazioni per le modalità delle porte e controlli

DTI / ISIN / Titolo principale della presentazione. La cena dei filosofi. Amos Brocco, Ricercatore, DTI / ISIN. 14 maggio 2012

Il costrutto monitor [Hoare 74]

Sistemi Operativi Esercizi Sincronizzazione

SAPIENZA Università di Roma Facoltà di Ingegneria dell Informazione, Informatica e Statistica

Il costrutto monitor [Hoare 74]

Capitolo 7: Sincronizzazione

Corso di Laurea in Ingegneria Gestionale Esame di Informatica a.a settembre 2011

Libreria Linux Threads. Threads nel S.O. Linux. Primitive per la gestione dei thread. Portabilità: libreria pthreads (Posix).

I/O su Socket TCP: read()

OTTAVA ESPERIENZA DI LABORATORIO. L elaborazione dei files in C

ACSO Programmazione di Sistema e Concorrente

CAPITOLO 24 I MONITOR

Ottava Esercitazione. introduzione ai thread java mutua esclusione

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Inizializzazione, Assegnamento e Distruzione di Classi

Java Virtual Machine

Il programmatore che c e in noi Lezione 12 Statements

Sistemi Operativi. Lezione 7 Comunicazione tra processi

Funzioni in C. Violetta Lonati

2. I THREAD. 2.1 Introduzione

Esercitazione 2! Mutex e semafori POSIX. 3 Novembre 2016

Esercitazione 2 Sincronizzazione con semafori. 31 Ottobre 2013

Ricorsione. (da lucidi di Marco Benedetti)

SISTEMI OPERATIVI. Sincronizzazione dei processi. Domande di verifica. Luca Orrù Centro Multimediale Montiferru 30/05/2007

Un esercizio d esame. Flavio De Paoli

istruzioni eseguite in ordine predeterminabile in base al codice del programma e dei valori dei dati in ingresso

Fondamenti di Informatica 2

Esercitazione 7. Procedure e Funzioni

Architetture dei Calcolatori e Sistemi Operativi

Introduzione al MATLAB c Parte 2

Processi programma processo processo Stati di un processo Attesa di caricamento new Pronto ( ready ) Esecuzione running Waiting ( in Attesa )

12 - Introduzione alla Programmazione Orientata agli Oggetti (Object Oriented Programming OOP)

La selezione binaria

void funzioneprova() { int x=2; cout<<"dentro la funzione x="<<x<<endl; }


Laboratorio di Sistemi Operativi

Gestione dei processi

Funzioni. Il modello console. Interfaccia in modalità console

Il problema del produttore e del consumatore. Cooperazione tra processi

10 - Programmare con gli Array

Coordinazione Distribuita

Informatica 3. Informatica 3. LEZIONE 6: Il controllo dell esecuzione. Lezione 6 - Modulo 1. Errori durante l esecuzione. Il controllo dell esecuzione

LinuxThreads: I thread nel sistema operativo LINUX: Linuxthreads. LinuxThreads. LinuxThreads

Introduzione. Coordinazione Distribuita. Ordinamento degli eventi. Realizzazione di. Mutua Esclusione Distribuita (DME)

APPELLO SCRITTO DI PROGRAMMAZIONE 1 CORSO DI LAUREA IN MATEMATICA UNIVERSITÀ DEGLI STUDI DI MILANO XI.2015

CAPITOLO 7 - SCAMBIO DI MESSAGGI

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Una funzione è detta ricorsiva se chiama, direttamente o indirettamente, se stessa. In C tutte le funzioni possono essere usate ricorsivamente.

Perche le CPU multicore

Sistemi Operativi mod. B. Sistemi Operativi mod. B A B C A B C P P P P P P < P 1, >

Strutture. Strutture e Unioni. Definizione di strutture (2) Definizione di strutture (1)

Computazione multi-processo. Condivisione, Comunicazione e Sincronizzazione dei Processi. Segnali. Processi e Threads Pt. 2

Sistemi Operativi. Lez. 13: primitive per la concorrenza monitor e messaggi

Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 2

ESERCIZI DI PROGRAMMAZIONE C IN AMBIENTE UNIX

Gestione della memoria centrale

Università degli Studi di Cassino Corso di Fondamenti di Informatica Puntatori. Anno Accademico 2010/2011 Francesco Tortorella

dall argomento argomento della malloc()

LinuxThreads: I thread nel sistema operativo LINUX: Linuxthreads

SC che operano su thread. pthread_create() etc...

Simulazione traffico urbano

Gestione dei File in C

Matematica - SMID : Programmazione Febbraio 2009 FOGLIO RISPOSTE

Compito Scritto di Ingegneria del Software. 10 gennaio Parte teorica, punti 14. Tempo a disposizione: 1 ora

Record locking con la system call fcntl

RICORSIONE - schema ricorsivo (o induttivo) si esegue l'azione S, su un insieme di dati D, mediante eventuale esecuzione di

Pronto Esecuzione Attesa Terminazione

Alcune regole di base per scrivere un programma in linguaggio C

Algoritmi di Ricerca. Esempi di programmi Java

Introduzione al linguaggio C Gli array

Dispensa di Informatica I.1

MODELLISTICA DI IMPIANTI E SISTEMI 2

Scheduling. Sistemi Operativi e Distribuiti A.A Bellettini - Maggiorini. Concetti di base

Appunti tratti dal videocorso on-line di Algoritmi e Programmazione Avanzata By ALeXio

ESERCIZIO 1 (Definizione funzioni passaggio parametri per copia)

Corso di Informatica Corso di Laurea in Ingegneria Gestionale a.a Secondo Compitino 17 Dicembre 2005

Programmazione I - Laboratorio

AXO. Operativo. Architetture dei Calcolatori e Sistema. programmazione di sistema

Deadlock e Starvation

Informa(ca Appun% dal laboratorio 2

Algoritmo. I dati su cui opera un'istruzione sono forniti all'algoritmo dall'esterno oppure sono il risultato di istruzioni eseguite precedentemente.

IPC System V. Code di messaggi

Transcript:

Thread: sincronizzazione Esercitazioni del 09 Ottobre 2009 Luca Fossati, Fabrizio Castro, Vittorio Zaccaria October 10, 2009

Sincronizzazione - 1 1 Esercizio 1: Sincronizzazione - 1 Qual è il problema nella seguente porzione di codice? int conto = 0; void * th_fun1( void * arg){ conto ++; printf( th_fun1 ha depositato sul conto - saldo: %d\n, conto); void * th_fun2( void * arg){ conto ++; printf( th_fun2 ha depositato sul conto - saldo: %d\n, conto); pthread_create(& th1, NULL, th_fun1, NULL); pthread_create(& th2, NULL, th_fun2, NULL); Il problema consiste nel fatto che i due thread operano sulla variabile conto con una sequenza lettura/scrittura (operatore ++) che puo rendere inconsistente lo stato della variabile stessa. Cio dovrebbe avvenire introducendo una mutua esclusione sulla sequenza di accesso alla variabile conto come nella seguente soluzione: int conto = 0; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; void * th_fun1( void * arg){ int temp,i; pthread_mutex_lock(& lock); printf( th_fun1: saldo del conto prima del deposito: %i\n, conto ); conto ++; pthread_mutex_unlock (& lock); printf( th_fun1 ha depositato sul conto - saldo: %d\n, conto );

Mutex - 1 2 void * th_fun2( void * arg){ int temp,i; pthread_mutex_lock(& lock); printf( th_fun2: saldo del conto prima del deposito: %i\n, conto ); conto ++; printf( th_fun2 ha depositato sul conto - saldo: %d\n, conto ); pthread_mutex_unlock (& lock); pthread_create(& th1, NULL, th_fun1, NULL); pthread_create(& th2, NULL, th_fun2, NULL); Esercizio 2: Mutex - 1 Problema del lettore-scrittore: un thread si occupa di scrivere una stringa, mentre altri si occupano della sua lettura. Non è possible avere letture e scritture contemporaneamente. Risolvere il problema usando solamente mutex. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; char buffer [10]; int pronto = 0; void * reader( void * arg){ while( pronto == 0 ); pthread_mutex_lock(& mutex); printf( Ho letto \ %s\ \n, buffer); pthread_mutex_unlock (& mutex); void * writer( void * arg){ pthread_mutex_lock(& mutex); sprintf(buffer, thread -%i, (int)pthread_self());

Sincronizzazione - 2 3 pronto = 1; pthread_mutex_unlock (& mutex); pthread_t th_r1, th_r2, th_r3; pthread_t th_w1; pthread_create(& th_r1, NULL, reader, NULL); pthread_create(& th_r2, NULL, reader, NULL); pthread_create(& th_r3, NULL, reader, NULL); pthread_create(& th_w1, NULL, writer, NULL); pthread_join( th_r1, NULL); pthread_join( th_r2, NULL); pthread_join( th_r3, NULL); pthread_join( th_w1, NULL); Esercizio 3: Sincronizzazione - 2 Qual è il problema nella seguente porzione di codice? char carattere = \ x0 ; void * th_fun1( void * arg){ printf( Letto %c\n, carattere); void * th_fun2( void * arg){ int i; carattere = ( rand()%93) +33; pthread_create(& th1, NULL, th_fun1, NULL);

Sincronizzazione - 2 4 pthread_create(& th2, NULL, th_fun2, NULL); Il problema sta nel fatto che th_fun2 dovrebbe essere eseguita sempre prima di th_fun1 in modo tale da leggere un carattere valido dal buffer. La serializzazione e un caso particolare di sincronizzazione che puo essere gestito attraverso dei semafori. L esercizio precedente puo essere risolto tramite l introduzione di un semaforo opportuno: # include <semaphore.h> char carattere = \ x0 ; sem_t semaforo; void * th_fun1( void * arg){ int i; sem_wait(& semaforo); printf( Letto %c\n, carattere); void * th_fun2( void * arg){ int i; carattere = ( rand()%93) +33; sem_post(& semaforo); srand( time( NULL ) ); sem_init(& semaforo, 0, 0); pthread_create(& th1, NULL, th_fun1, NULL); pthread_create(& th2, NULL, th_fun2, NULL);

Semafori - 1 5 Esercizio 4: Semafori - 1 Quattro amici fanno una scommessa, il premio per il vincitore è di poter fare bere uno dei rimanenti amici. Chi vince la scommessa sceglie casualmente a chi tocca bere il cocktail tutto d un fiato mentre gli altri stanno a guardare. Alla fine, viene proposta un ulteriore scommessa e il gioco va avanti all infinito. Rappresentare il problema utilizzando i semafori. # include <semaphore.h> sem_t sem_turno [3]; sem_t sem_bevuto; void * amico( void * arg){ while(1){ sem_wait(&sem_turno[(int)arg]); // E STATO SCELTO PER BERE sem_post(& sem_bevuto); // HA FINITO DI BERE void * vincitore( void * arg){ int turno = 0; while(1){ sem_wait(& sem_bevuto); turno = rand()%3; sem_post(&sem_turno[turno]); pthread_t th_amici [3]; pthread_t th_vincitore; int i = 0; for(i = 0; i < 3; i++){ sem_init(& sem_turno[i], 0, 0); sem_init(& sem_bevuto, 0, 1); for(i = 0; i < 3; i++){ pthread_create (&( th_amici[i]), NULL, amico, ( void *) i); pthread_create(& th_vincitore, NULL, vincitore, NULL); for(i = 0; i < 3; i++){

Semafori - 2 6 pthread_join( th_amici[i], NULL); pthread_join( th_vincitore, NULL); Esercizio 5: Semafori - 2 Negozio del barbiere: il barbiere dorme fino a che non ci sono clienti: all arrivo di un cliente esso può: 1. svegliare il barbiere (nel caso stesse dormendo); 2. sedersi e aspettare che il barbiere abbia finito con il cliente che sta radendo al momento; 3. se tutte le sedie della sala d attesa sono occupate il cliente se ne va. Implementare un programma che simula il comportamento appena descritto. Si fa l ipotesi che la particolare implementazione dei semafori sblocchi i thread secondo l ordine di chiamata della sem_wait. # include <semaphore.h> # define NUMERO_DI_SEDIE 5 # define NUMERO_DI_CLIENTI 20 sem_t sem_barbiere_disponibile, sem_cliente_arrivato; pthread_mutex_t stanza = PTHREAD_MUTEX_INITIALIZER; int sedie_disponibili = NUMERO_DI_SEDIE; void * barbiere( void * arg ) { while( 1 ) { // il barbiere dorme aspettando l arrivo di un cliente sem_wait( & sem_cliente_arrivato ); // il barbiere si sveglia e fa accomodare il cliente sleep(1) /* TEMPO DI SERVIZIO */ sem_post( & sem_barbiere_disponibile ); // il barbiere e pronto a fare la barba void * cliente( void * arg ) { pthread_mutex_lock( & stanza );

Semafori - 2 7 if( sedie_disponibili > 0 ) { // il cliente si siede in sala d attesa sedie_disponibili --; pthread_mutex_unlock( & stanza ); // il cliente avvisa il barbiere della sua presenza sem_post( & sem_cliente_arrivato ); // il cliente aspetta che il barbiere sia disponibile sem_wait( & sem_barbiere_disponibile ); pthread_mutex_lock( & stanza ); // il cliente si alza dalla sedia e si accomoda sulla poltrona del barbiere sedie_disponibili ++; pthread_mutex_unlock( & stanza ); // finalmente il cliente riesce a farsi la barba else { // il cliente esce dal negozio del barbiere pthread_mutex_unlock( & stanza ); int main( int argc, char ** argv ) { pthread_t th_clienti[ NUMERO_DI_CLIENTI ]; pthread_t th_barbiere; int i; sem_init( & sem_barbiere_disponibile, 0, 0 ); sem_init( & sem_cliente_arrivato, 0, 0 ); pthread_create( & th_barbiere, NULL, barbiere, NULL ); for( i = 0; i < NUMERO_DI_CLIENTI; i++ ) pthread_create( & th_clienti[ i ], NULL, cliente, NULL ); for( i = 0; i < NUMERO_DI_CLIENTI; i++ ) pthread_join( th_clienti[ i ], NULL ); pthread_join( th_barbiere, NULL ); La soluzione usa due semafori ed un mutex: i due semafori sono usati per sapere quando il barbiere è pronto (sem_barbiere_disponibile) e quanti clienti sono in attesa nella stanza(sem_cliente_arrivato). Il mutex (stanza) viene invece usato per garantire la mutua esclusione nella modifica e nell accesso alle sedie della stanza.

Semafori: implementazione tramite mutex 8 Esercizio 6: Semafori: implementazione tramite mutex La seguente porzione di codice mostra come creare un semaforo utilizzando due mutex ed un ciclo di busy wait. Il semaforo viene quindi utilizzato da due thread per sincronizzarsi in maniera seriale. unsigned int valoresemaforo; pthread_mutex_t mutex_sem_mod = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t mutex_sem_wait = PTHREAD_MUTEX_INITIALIZER; void my_sem_init( unsigned int valoreiniziale){ valoresemaforo = valoreiniziale; void my_sem_post (){ pthread_mutex_lock(& mutex_sem_mod); valoresemaforo ++; pthread_mutex_unlock (& mutex_sem_mod); void my_sem_wait (){ pthread_mutex_lock(& mutex_sem_wait); while( valoresemaforo <= 0) ; pthread_mutex_lock(& mutex_sem_mod); valoresemaforo --; pthread_mutex_unlock (& mutex_sem_mod); pthread_mutex_unlock (& mutex_sem_wait); void * th_fun1( void * arg){ my_sem_post (); void * th_fun2( void * arg){ my_sem_wait (); my_sem_init (0); printf( Creazione thread\n ); pthread_create(& th1, NULL, th_fun1, NULL); pthread_create(& th2, NULL, th_fun2, NULL); printf( Attesa sincronizzazione\n );

Produttore/Consumatore - 1 9 printf( Fine programma\n ); Esercizio 7: Produttore/Consumatore - 1 Individuare il problema della seguente versione del problema produttore/consumatore: char buffer; int fine = 0; void * scrivi( void * arg){ int i; for (i=0; i < 5; i++){ buffer = a + i; printf( scrivi: ho scritto %c \n, buffer ); sleep(3); fine = 1; void * leggi( void * arg){ char miobuffer = \ x0 ; while (fine == 0){ sleep(1); miobuffer = buffer; printf( leggi: ho letto %c \n, miobuffer ); int main( void){ pthread_create(& th1, NULL, & scrivi, NULL); pthread_create(& th2, NULL, & leggi, NULL); Non essendo usato alcun meccanismo di sincronizzazione, non è garantito l accesso corretto alla variabile buffer. In particolare, il thread leggi potra leggere piu volte la stessa lettera dal buffer.

Produttore/Consumatore - 2 10 Esercizio 8: Produttore/Consumatore - 2 Soluzione corretta ed efficiente implementata utilizzando i semafori: sono necessari due semafori: vuoto per segnalare al thread scrivi (il produttore), che il consumatore ha letto il buffer; pieno per segnalare al thread leggi (il consumatore), che il produttore ha scritto il buffer. # include <semaphore.h> char buffer; int fine = 0; sem_t pieno, vuoto; void * scrivi( void * arg){ int i; for (i=0; i < 5; i++){ sem_wait(& vuoto); buffer = a + i; sem_post(& pieno); sem_wait(& vuoto); fine = 1; sem_post(& pieno); void * leggi( void * arg){ char miobuffer = \ x0 ; while ( 1 ){ sem_wait(& pieno); if( fine!= 0 ) miobuffer = buffer; sem_post(& vuoto); int main( void){ sem_init(& pieno, 0, 0); sem_init(& vuoto, 0, 1); pthread_create(& th1, NULL, & scrivi, NULL); pthread_create(& th2, NULL, & leggi, NULL);

Sequenze di esecuzione - 1 11 Esercizio 9: Sequenze di esecuzione - 1 Dato il seguente programma, stampare tutte i possibili output, supponendo che l istruzione printf di stampa a schermo sia atomica (cio supponendo che una volta inizata la stampa dell argomento di una printf) essa termini prima che nel sistema venga eseguita un altra direttiva printf. pthread_mutex_t mutexa = PTHREAD_MUTEX_INITIALIZER; void * th_fun1( void * arg){ pthread_mutex_lock(& mutexa); printf( th_fun1-1\ n ); pthread_mutex_unlock (& mutexa); printf( th_fun1-2\ n ); void * th_fun2( void * arg){ pthread_mutex_lock(& mutexa); printf( th_fun2-1\ n ); printf( th_fun2-2\ n ); pthread_mutex_unlock (& mutexa); pthread_create(& th1, NULL, th_fun1, NULL); pthread_create(& th2, NULL, th_fun2, NULL); Indicare almeno due sequenze di esecuzione e spiegare a parole quali sono tutte le possibili sequenze. Soluzione I thread th1 e th2 vengono mandati in esecuzione in contemporanea: a questo punto due sequenze di esecuzione sono possibili:

Sequenze di esecuzione - 1 12 1. th1 acuiqsice il lock sul mutexa prima di th2: viene stampato th_fun1-1. th_fun2-1 e th_fun2-2 vengono sicuramente stampati dopo th_fun1-1 e in un orine imprecisato rispetto a th_fun1-2. In poche parole tutte le sequenze sono valide purchè th_fun1-1 venga stampato prima di th_fun2-1 e th_fun2-2. Le possibili sequenze di esecuzione in questo caso sono: th_fun1-1 th_fun1-2 th_fun2-1 th_fun2-2 th_fun1-1 th_fun2-1 th_fun1-2 th_fun2-2 th_fun1-1 th_fun2-1 th_fun2-2 th_fun1-2 2. th2 acuiqsice il lock sul mutexa prima di th1: vengono stampati th_fun2-1 e th_fun2-2. th_fun1-1 viene sicuramente stampato dopo di essi; th_fun1-2 segue. In questo caso esiste solo una sequenza di esecuzione: th_fun2-1 th_fun2-2 th_fun1-1 th_fun1-2 In parole povere, il mutex serve per evitare che th_fun1-1 venga stampata tra th_fun2-1 e th_fun2-2.