= PTHREAD_MUTEX_INITIALIZER

Похожие документы
Perche le CPU multicore

I thread nel sistema operativo LINUX: Linuxthreads

Monitor pthreads. Esercizio

Sistemi Operativi (M. Cesati)

Il costrutto monitor

Thread: sincronizzazione Esercitazioni del 09 Ottobre 2009

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

Sistemi Operativi L-A. Esercizi 14 Giugno Esercizio monitor

I Thread in Java e POSIX

Sistemi Operativi Anno Accademico 2011/2012. Segnali: Interrupt software per la gestione di eventi asincroni

2. I THREAD. 2.1 Introduzione

3.2 Concorrenza, parallelismo e parallelismo reale

Realizzazione di Politiche di Gestione delle Risorse: i Semafori Privati

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

Il costrutto monitor [Hoare 74]

Meccanismi di sincronizzazione: Semafori e Monitor

Java Virtual Machine

Informatica B. Sezione D. Scuola di Ingegneria Industriale Laurea in Ingegneria Energetica Laurea in Ingegneria Meccanica

SISTEMI OPERATIVI. Sincronizzazione in Java (Monitor e variabili condizione in Java)

Introduzione. Meccanismi di sincronizzazione: Semafori e Monitor. Semafori - Definizione. Semafori - Descrizione informale

Il costrutto monitor [Hoare 74]

Java threads (2) Programmazione Concorrente

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

Deadlock e Starvation

Sistemi Operativi. Lezione 7 Comunicazione tra processi

Capitolo 7: Sincronizzazione

Sistemi Operativi Sincronizzazione tra Processi

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

PROGRAMMA DISCIPLINARE SVOLTO a. s / 2016

puntatori Lab. Calc. AA 2007/08 1

Gli array. Gli array. Gli array. Classi di memorizzazione per array. Inizializzazione esplicita degli array. Array e puntatori

Posix Threads: l evoluzione dei processi UNIX

Monitor. Introduzione. Struttura di un TDA Monitor

Esercizi sugli Oggetti Monitor

CAPITOLO 24 I MONITOR

2) FILE BINARI: è una sequenza di byte avente una corrispondenza uno a uno con la sequenza ricevuta dal dispositivo esterno.

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

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

Unità Didattica 3 Linguaggio C. Generalità sulle Funzioni. Variabili locali e globali. Passaggio di parametri per valore.

Gestione dei processi

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

Multithreading in Java. Fondamenti di Sistemi Informativi

Implementazione dei monitor tramite semafori Attesa condizionale Sincronizzazione nei sistemi operativi reali Transazioni atomiche

Sistemi Operativi. Bruschi Monga Re. Sincronizzazione con monitor pthreads. Shell Shell programming Esercizi I/O Esercizi Tabella riassuntiva

Gestione delle eccezioni in Java

Corso di Sistemi Operativi

progam ponteasensounicoalaternato ; type dir = ( nord, sud );

Allocazione dinamica della memoria - riepilogo

Java Native Interface Appunti

Input/output in C e in C++

Sistemi Operativi Esercizi Sincronizzazione

Esercizi sul Monitor in Java

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

Relazione tra thread e processi

Laboratorio di Algoritmi e Strutture Dati. La gestione della memoria dinamica Heap

Homework HWC1 di Programmazione Concorrente 13 novembre 2014 anno accademico 2014/2015

T 1. Per un processo con più thread di controllo, lo stato di avanzamento della computazione di ogni thread è dato da:

Funzioni in C. Violetta Lonati

SISTEMI OPERATIVI. Nucleo di un SO. Il Nucleo. Il nucleo di un SO Gestione delle interruzioni Sincronizzazione tra processi Dispatcher. 06.

Sincronizzazione e comunicazione tra processi in Unix. usati per trasferire ad un processo l indicazione che un determinato evento si è verificato.

3. Terza esercitazione autoguidata: progetto gestione voli

Sottoprogrammi: astrazione procedurale

Le funzioni in C. I programmi C sono costituiti da definizioni di variabili e funzioni.

Terza Esercitazione. Unix - Esercizio 1. Unix System Call Exec Java Introduzione Thread

Programmazione concorrente in Java. Dr. Paolo Casoto, Ph.D

System call fcntl e record locking

I THREAD O PROCESSI LEGGERI Generalità

Gestione dei File in C

SERVIZIO GRUPPO BANCA POPOLARE DI BARI

SISTEMI OPERATIVI. Deadlock (blocco critico) Domande di verifica. Luca Orrù Centro Multimediale Montiferru 04/06/2007

Programmazione concorrente in Java

Sincronizzazione dei processi

Ingegneria del Software

SISTEMI OPERATIVI. Sincronizzazione in Java (Semafori e barriere) Patrizia Scandurra (MODULO DI INFORMATICA II) LABORATORIO

I puntatori e l allocazione dinamica di memoria

Le system call: fork(), wait(), exit()

Esercitazioni 7 e 8. Bounded Buffer con sincronizzazione Java (1)

Corso di Laboratorio di Sistemi Operativi

Linguaggio C - Funzioni

Un esercizio d esame. Flavio De Paoli

LA SINCRONIZZAZIONE TRA PROCESSI

Processi parte V. Processi parte V. Sincronizzazione dei processi mediante monitor: Sintassi Funzionamento Implementazione

Sistemi Operativi. Gianluca Della Vedova. Sistemi Operativi. Gianluca Della Vedova. Sistemi Operativi. Gianluca Della Vedova.

Introduzione al linguaggio C Gli array

costruttori e distruttori

Транскрипт:

MUTEX Prof.ssa Sara Michelangeli Quando si programma in modalità concorrente bisogna gestire le problematiche di accesso alle eventuali sezioni critiche. Una sezione critica è una sequenza di istruzioni in cui un thread accede a risorse comuni ad altri thread concorrenti. In particolare, quando una sezione critica prevede modifiche di variabili condivise, è necessario attuare una protezione che garantisca la mutua esclusione, cioè il divieto di accesso contemporaneo alla risorsa comune. Per i Thread POSIX la protezione delle sezioni critiche può essere ottenuta con una variabile mutex (Mutual Exclusion). Una variabile mutex è un semaforo binario che ha valore 0 (occupato), 1 (libero). Un mutex, posto a protezione di una sezione critica, previene la race condition (interferenza): dà l'accesso all'esecuzione ad un solo thread alla volta, lasciando fuori gli altri thread, fino a che il thread che sta occupando la sezione non ne ha terminato l'esecuzione. Per creare un mutex è necessario usare una variabile di tipo pthread_mutex_t, sempre di libreria pthread, che contiene informazioni sul nome del mutex, il proprietario, la struttura associata al mutex, la coda dei processi sospesi in attesa che mutex sia libero ecc. La dichiarazione ha la sintassi pthread_mutex_t semaforo; L'inizializzazione di una variabile mutex puo' essere statica o dinamica. L'inizializzazione statica avviene con l'uso della macro PTHREAD_MUTEX_INITIALIZER. L'istruzione pthread_mutex_t semaforo = PTHREAD_MUTEX_INITIALIZER; inizializza la variabile semaforo a occupato L'inizializzazione dinamica si attua con l'uso della funzione init il cui prototipo è int pthread_mutex_init( pthread_mutex_t *mutex, pthread_mutex_attr_t *mattr ) i cui parametri sono un puntatore alla variabile mutex e gli attributi del semaforo che, al valore NULL di default, inizializzano il semaforo a libero. L'istruzione pthread_mutex_init(&semaforo,null); inizializza la variabile semaforo a libero. Le funzioni base che operano su mutex e che consentono la gestione della mutua esclusione, l'attività più impegnativa per chi si occupa di programmazione concorrente, sono le due funzioni di lock e unlock. La funzione di blocco ha prototipo int pthread_mutex_lock(pthread_mutex_t * semaforo) accetta un singolo semaforo, e, posta all'inizio della sezione critica ha lo scopo di sospendere l'accesso alla sezione per tutti i thread concorrenti a quello in esecuzione, fino allo sblocco della stessa.quando vi è l'istruzione pthread_mutex_lock(&semaforo); solo il thread che è riuscito ad eseguire la lock prosegue l esecuzione e puo' accedere ai dati, gli altri thread chiamanti rimangono bloccati, vanno in attesa. Come si vede nel prototipo la lock è una funzione che restituisce un intero, uno zero, in caso di successo, o un codice di errore diverso da zero in caso di fallimento. Esiste anche una variante della funzione lock, la trylock, non bloccante per il thread chiamante. La funzione di sblocco ha prototipo int pthread_mutex_unlock(pthread_mutex_t * semaforo)

ed ha l'effetto di liberare la variabile mutex. L'istruzione pthread_mutex_unlock(&semaforo) posta al termine della sezione critica sblocca il semaforo. A questo punto un altro thread, che ha precedentemente chiamato la lock della mutex, in coda per accedere alla sezione critica, viene svegliato potrà terminare la lock (bloccando a sua volta l'accesso ad altri concorrenti) e procedere con l'esecuzione. Il valore di ritorno della funzione è analogo a quello della lock. E' possibile eliminare un mutex con la funzione int pthread_mutex_destroy( pthread_mutex_t *mutex ) che ha come parametro il puntatore al thread da distruggere e ritorna un valore 0 in caso di successo Condition Variable Come abbiamo appena visto i mutex hanno un importantissimo compito, ma, il prezzo, in termini di efficienza del programma potrebbe essere molto alto e, di fatto, rendere inutile la concorrenza. Infatti i threads in attesa dello sblocco si potrebbero trovare impegnati in onerose attività di busypolling (sequenze periodiche di test per il verificarsi di eventi). Per questo l'uso dei mutex viene spesso associato alle condition variables, variabili che consentono la sincronizzazione tra thread che condividono un mutex, e che permettono ai threads di sospendere la propria esecuzione in attesa del verificarsi di determinate condizioni su dati condivisi. E' da evitare l'uso di condition variables senza mutex, per scongiurare pericolose situazioni di deadlock. Inoltre è opportuno ribadire che una variable condition senza mutex non assicura mutua esclusione. Per creare una condition variable è necessario usare una variabile di tipo pthread_cond_t, sempre di libreria pthread. La dichiarazione ha la sintassi pthread_cond_t cond; Come per i mutex anche l'inizializzazione di una variable condition puo' essere statica o dinamica, statica con l'istruzione pthread_cond_t cond = PTHREAD_COND_INITIALIZER; e dinaminca con l'uso della funzione init int pthread_cond_init( pthread_cond _t *cond, pthread_cond_attr_t *condattr ) i cui parametri sono un puntatore alla variabile cond e gli attributi della variabile di condizione, al valore NULL di default. Le funzioni base che operano con variable condition sono la sospensione, wait, per mettere un thread in attesa, e il risveglio, signal, per risvegliare i thread sospesi La funzione di per mettere in attesa un thread è pthread_cond_wait(pthread_cond_t cond, pthread_mutex_t * semaforo) ha come parametri la variabile di condizione e il mutex che regola l'accesso alla sezione critica. Questa funzione blocca il thread chiamante sulla coda associata a cond, e il mutex semaforo viene sbloccato in modo da liberare la sezione critica ad un altro thread. Questa funzione deve essere chiamata quando il mutex è bloccato. La funzione di per risvegliare un thread bloccato è pthread_cond_signal(pthread_cond_t cond) il thread che viene svegliato è il primo della coda dei sospesi, se non vi è nessun processo in attesa la funzione viene ignorata. Per risvegliare tutti i thread in attesa si usa un funzione di broadcast pthread_cond_broadcast(pthread_cond_t cond)

che si rivolge a tutti i thread in attesa su quella condizione. Esempio Mettiamo in pratica i concetti espressi con un esempio classico della sincronizzazione, il problema produttore-consumatore. Si parla di problema produttore-consumatore quando due sezioni di un programma lavorano in concorrenza con compiti specifici: una produce un dato, l'altra lo consuma, in una alternanza ciclica, e, naturalmente, devono essere sincronizzate tra loro. Pensiamo ad esempio ad una variabile condivisa, con un thread che si occupa di acquisirla da input e un altro di stamparla. Il consumatore non deve stampare finchè il produttore non ha letto da input il dato, ma il produttore non deve leggere finchè il consumatore non ha stampato il dato precedente. Implementiamo un primo codice privo di mutex e variable condition #include<stdio.h> #include <pthread.h> int variabilecondivisa; //variabile che dovrebbe essere utilizzata in mutua esclusione //thread di acquisizione: produttore void* threadacquisisci(void* arg) while (1) //ciclo infinito printf(" \n"); scanf("%d",&variabilecondivisa); fflush(stdin); pthread_exit(null); //thread di stampa :consumatore void* threadstampa (void* arg) while(1) //ciclo infinito sleep(3);//attesa printf ("dato stampato è %d \n",variabilecondivisa); pthread_exit(null); int main() pthread_t miot;//thread per produrre il dato pthread_t miot2;//thread per stampare il dato //creazione dei thread pthread_create(&miot,null,threadacquisisci,null); pthread_create(&miot2,null,threadstampa,null); //attendo terminazione thread pthread_join(miot,null); pthread_join(miot2,null); //fine programma printf("programma terminato");

L'esecuzione darà risultati del tipo 3 4 dato stampato è 4 6 dato stampato è 6 8 ecc. E' evidente che l'uso della sleep non è in alcun modo sufficiente a sincronizzare i due thread, si origina una sequenza chiaramente errata. Inoltre se smettiamo di inserire vediamo che il consumatore continua a eseguire codice, stampando più volte l'ultimo dato acquisito Ora correggiamo il programma garantendo la sincronizzazione e la mutua esclusione con l'uso di mutex e variable condition. #include<stdio.h> #include <pthread.h> int variabilecondivisa; //variabile in mutua esclusione //mutex per la mutua esclusione identificatore semaforo pthread_mutex_t semaforo; //variable condition per la sincronizzazione identificatore empty pthread_cond_t empty; //variable condition per la sincronizzazione identificatore empty pthread_cond_t full; //thread di acquisizione: produttore void* threadacquisisci(void* arg) while(1) //attesa del segnale di utilizzo del dato precedente //non si deve leggere finchè non è avvenuta la stampa precedente pthread_cond_wait(&empty,&semaforo); //lock per l'accesso alla sezione critica //il dato deve essere letto non puo' ancora essere prelevato pthread_mutex_trylock(&semaforo); printf(" \n"); scanf("%d",&variabilecondivisa); fflush(stdin);

//invio segnale risveglio consumatore: il nuovo dato è stato prodotto pthread_cond_signal(&full); //unlock per uscita dalla sezione critica //il dato puo' essere prelevato pthread_mutex_unlock(&semaforo); pthread_exit(null); //thread di stampa :consumatore void* threadstampa (void* arg) //per la prima produzione pthread_cond_signal(&empty); while(1) //attesa del segnale del produttore //non si deve stampare finchè non è avvenuta la lettura pthread_cond_wait(&full,&semaforo); //lock per l'accesso alla sezione critica //il dato prima di una nuova produzione deve essere stampato pthread_mutex_trylock(&semaforo); printf ("dato stampato è %d \n",variabilecondivisa); //unlock per uscita dalla sezione critica //il dato puo' essere scritto pthread_mutex_unlock(&semaforo); //sveglia il thread produttore in attesa pthread_cond_signal(&empty); pthread_exit(null); int main() pthread_t produttore;//thread per produrre il dato pthread_t consumatore;//thread per stampare il dato pthread_mutex_init(&semaforo,null);//inizializzo semaforo a libero pthread_cond_init(&empty, NULL); pthread_cond_init(&full, NULL); //creazione dei thread pthread_create(&produttore,null,threadacquisisci,null); pthread_create(&consumatore,null,threadstampa,null); //attendo terminazione thread pthread_join(produttore,null); pthread_join(consumatore,null); //fine programma printf("programma terminato");

L'esecuzione sarà del tipo 3 dato stampato è 3 4 dato stampato è 4 1 3 dato stampato è 3 4 dato stampato è 4 1 dato stampato è 1 5 dato stampato è 5 6 dato stampato è 6 7 dato stampato è 7 9 dato stampato è 9 dato stampato è 1 5 dato stampato è 5 6 dato stampato è 6 7 dato stampato è 7 9 dato stampato è 9 cioè correttamente sincronizzata.