Semafori. Semafori classici con i thread POSIX 2

Documenti analoghi
Sistemi Operativi. Esercitazione 9. Corso di Laurea Triennale in Ingegneria Informatica.

Sistemi Operativi. Esercitazione 8. Corso di Laurea Triennale in Ingegneria Informatica.

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

Sistemi Operativi. Esercitazione 8 Ripasso CRON Semaphore.h Segnali Shell e processi. Corso di Laurea Triennale in Ingegneria Informatica

Thread POSIX. Thread POSIX: aspetti preliminari. Thread POSIX. Thread. Introduzione ai thread POSIX. Sincronizzazione

Cosa sono i semafori?

Tipi di POSIX Semaphores

Thread: sincronizzazione Esercitazioni del 16 Ottobre 2009

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

Esercitazione 2! Mutex e semafori POSIX. 3 Novembre 2016

Sincronizzazione. I semafori Stefano Quer Dipartimento di Automatica e Informatica Politecnico di Torino

Corso di Laboratorio di Sistemi Operativi

I thread nel sistema operativo LINUX: Linuxthreads

Sincronizzazione fra processi

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

File binari e file di testo

Il linguaggio C. Breve panoramica su stdio.h

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

il tipo di parallelismo dipende dal grado di cooperazione

Introduzione al Multithreading

Thread: sincronizzazione Esercitazioni del 09 Ottobre 2009

Sistemi Operativi (M. Cesati)

Esercitazione n.1! 23 Ottobre Obiettivi: Introduzione alla programmazione pthreads:

CAPITOLO 17 PROBLEMI DEL PRODUTTORE/CONSUMATORE v1

Sistemi Operativi (M. Cesati)

ACSO Programmazione di Sistema e Concorrente

Input/Output. Lettura e scrittura Caratteri e Stringhe: Terminale e file. Input/output. caratteri stringhe formattato ascii binari

Le strutture. Una struttura C è una collezione di variabili di uno o più tipi, raggruppate sotto un nome comune.

CAPITOLO 22 PROBLEMA DEL PRODUTTORE/CONSUMATORE

C: panoramica. Violetta Lonati

Indice. La gestione dei file in C e gli stream. Apertura e chiusura di un file. Operazioni sui file. Accesso sequenziale e non sequenziale

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

Gestione dei file. Stefano Ferrari. Università degli Studi di Milano Programmazione. anno accademico

I thread nel sistema operativo LINUX: Linuxthreads

Thread thread lightweight process

Corso di Laboratorio di Sistemi Operativi A.A

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

Creazione di thread. In Linux si utilizzano le librerie pthread (POSIX thread) per lavorare con i thread:

System Call per la gestione dei semafori in Linux. Semafori: modello concettuale. Creazione ed inizializzazione di un semaforo

Una stringa di caratteri in C è un array di caratteri terminato dal carattere '\0' a p e \0

Architettura degli Elaboratori 2

Unità Didattica 4 Linguaggio C. Vettori. Puntatori. Funzioni: passaggio di parametri per indirizzo.

Sistemi Operativi. Lezione 7-bis Esercizi

GESTIONE DEI FILE IN C. Docente: Giorgio Giacinto AA 2008/2009

Cenni ai Problemi classici di Sincronizzazione Processi Concorrenti. E. Mumolo

Gestione dinamica della memoria

Operazioni su file di caratteri

Sommario. Manipolazione sequenziale di file in C Funzioni di base per I/O di file

Perche le CPU multicore

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

Laboratorio di Sistemi Operativi

Gestione dei file in C

Corso di Programmazione Concorrente Processi. Valter Crescenzi

Thread. La libreria Pthread Stefano Quer Dipartimento di Automatica e Informatica Politecnico di Torino

System Calls per la Gestione dei Processi

Stringhe e allocazione dinamica della memoria

Sistemi operativi - Concetti ed esempi -Settima edizione

Informazioni Utili. Fondamenti di Informatica L-B (L-Z) Esercitazioni. A.A. 2005/06 Tutor: Loris Cancellieri

Capitolo 5 -- Stevens

I Thread. I Thread. Se creiamo un nuovo processo con la fork, questo erediterà dal padre

Informatica 1. Corso di Laurea Triennale in Matematica. Gianluca Rossi

Le strutture. Una struttura C è una collezione di variabili di uno o più tipi, raggruppate sotto un nome comune.

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

LinuxThreads. LinuxThreads: monitor & variabili condizione

Input / Output. Come già detto, input e output sono realizzati in C da funzioni di stdio.h all'interno della libreria standard

Unità Didattica 1 Linguaggio C. Fondamenti. Struttura di un programma.

La gestione della memoria dinamica Heap

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

Il linguaggio C. Notate che...

Modelli di programmazione parallela

Le risorse. Alcune definizioni

I THREAD. thread 2. thread 1

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

LIBRERIE STANDARD in C. LIBRERIE STANDARD in C

Comunicazione tra processi: pipe Le pipe sono un meccanismo UNIX di Inter Process Communication (IPC)

Il linguaggio C. Puntatori e dintorni

Input/output da file I/O ANSI e I/O UNIX FLUSSI E FILE FLUSSI FLUSSI di TESTO FLUSSI BINARI FILE

Sistemi Operativi (M. Cesati)

ERRATA CORRIGE. void SvuotaBuffer(void); void SvuotaBuffer(void) { if(getchar()!=10) {svuotabuffer();} }

Addendum alle chiamate di sistema per la gestione processi. E Mumolo

Soluzioni ai problemi di Mutua Esclusione Primitive di sincronizzazione. Soluzioni ai problemi di Mutua EsclusionePrimitive di sincronizzazione

Esercizi di utilizzo del semaforo semplice di competizione per l'uso di una risorsa comune

perror: individuare l errore quando una system call restituisce -1

Monitor. Le procedure entry sono le sole operazioni che possono essere utilizzate dai processi per accedere alle variabili comuni.

Input/Output di numeri

Esercitazione [11] Riepilogo sui Semafori. Sistemi di Calcolo - Secondo modulo (SC2) Programmazione dei Sistemi di Calcolo Multi-Nodo

Input / Output. Come già detto, input e output sono realizzati in C da funzioni di stdio.h all'interno della libreria standard

Fondamenti di Informatica L-B (L-Z) Esercitazioni. A.A. 2007/08 Tutor: Barbara Pettazzoni

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

System call per la gestione di processi

INTERPROCESS COMMUNICATION 27

Sincronizzazione dei processi. Capitolo 5 -- Silberschatz

void char void char @param void int int int int

Panoramica Introduttiva su Inter-Process Communication (IPC)

2. I THREAD. 2.1 Introduzione

Sistemi Operativi. Marzo-Giugno 2011 matricole congrue 0 mod 3. Controllo dei processi - I

Complementi. - Ridefinizione di tipo - - Costrutto switch - - Programmazione su più file - - Parametri della funzione main - Funzione system -

Esercizio 1 (15 punti)

Relazione tra thread e processi

STRINGHE: ARRAY DI CARATTERI! a p e \0

Transcript:

Semafori classici

Semafori I semafori sono primitive, implementate attraverso dei contatori, fornite dal sistema operativo per permettere la sincronizzazione tra processi e/o thread. Per queste primitive è garantita l'atomicità. Quindi, ogni modifica o check del valore di un semaforo può essere effettuata senza sollevare race conditions. Semafori classici con i thread POSIX 2

Race condition Più processi accedono concorrentemente agli stessi dati, e il risultato dipende dall'ordine di interleaving dei processi. Frequenti nei sistemi operativi multitasking, sia per dati in user space sia per strutture in kernel. Estremamente pericolose: portano al malfunzionamento dei processi coo-peranti, o anche (nel caso delle strutture in kernel space) dell'intero sistema difficili da individuare e riprodurre: dipendono da informazioni astratte dai processi (decisioni dello scheduler, carico del sistema, utilizzo della memoria, numero di processori,... ) Semafori classici con i thread POSIX 3

Mutex vs Semaforo (1 di 2) Il mutex è un tipo definito "ad hoc" per gestire la mutua esclusione quindi il valore iniziale può essergli assegnato anche in modo statico mediante la macro PTHREAD_MUTEX_INITIALIZER. Al contrario un semaforo come il sem_t deve essere di volta in volta inizializzato dal programmatore col valore desiderato. Semafori classici con i thread POSIX 4

Mutex vs Semaforo (2 di 2) Un semaforo può essere impiegato come un mutex Differenza sostanziale: un mutex deve sempre essere sbloccato dal thread che lo ha bloccato, mentre per un semaforo l operazione post può non essere eseguita dal thread che ha eseguito la chiamata wait. inizializzo un mutex; inizializzo un semaforo (1); pthread_mutex_lock(&mutex); sezione critica pthread_mutex_unlock(&mutex); sem_wait(&sem); sezione critica sem_post(&sem); Semafori classici con i thread POSIX 5

Semafori classici (generali) (1 di 2) Semafori il cui valore può essere impostato dal programmatore utilizzati per casi più generali di sincronizzazione esempio: produttore consumatore Interfaccia operazione wait operazione post (signal) Semafori classici con i thread POSIX 6

Semafori classici (generali) (2 di 2) Semafori classici e standard POSIX non presenti nella prima versione dello standard introdotti insieme come estensione real-time con lo standard IEEE POSIX 1003.1b (1993) Utilizzo associati al tipo sem_t includere l header #include <semaphore.h> #include <errno.h> Semafori classici con i thread POSIX 7

errno Quasi tutte le funzioni delle librerie del C sono in grado di individuare e riportare condizioni di errore, ed è una norma fondamentale di buona programmazione controllare sempre che le funzioni chiamate si siano concluse correttamente. In genere le funzioni di libreria usano un valore speciale per indicare che c'è stato un errore. Di solito questo valore è -1 o un puntatore NULL o la costante EOF (a seconda della funzione); ma questo valore segnala solo che c'è stato un errore, non il tipo di errore. Per riportare il tipo di errore il sistema usa la variabile globale errno definita nell'header errno.h Il valore di errno viene sempre impostato a zero all'avvio di un programma. La procedura da seguire è sempre quella di controllare errno immediatamente dopo aver verificato il fallimento della funzione attraverso il suo codice di ritorno. Semafori classici con i thread POSIX 8

Stato di errore (1 di 2) Per verificare la presenza di uno stato di errore si usa la funzione ferror() che restituisce un valore diverso da zero se questo stato esiste effettivamente: int ferror (FILE *flusso_di_file); Per interpretare l'errore annotato nella variabile errno e visualizzare direttamente un messaggio attraverso lo standard error, si può usare la funzione perror() void perror (const char *s); La funzione perror() mostra un messaggio in modo autonomo, aggiungendo davanti la stringa che può essere fornita come primo argomento Semafori classici con i thread POSIX 9

Stato di errore (2 di 2) L'esempio seguente mostra un programma completo e molto semplice, in cui si crea un errore, tentando di scrivere un messaggio attraverso lo standard input. Se effettivamente si rileva un errore associato a quel flusso di file, attraverso la funzione ferror(), allora si passa alla sua interpretazione con la funzione strerror() #include <stdio.h> #include <errno.h> #include <string.h> int main (void){ char *cp; fprintf (stdin, Hello world!\n"); if (ferror (stdin){ cp = strerror (errno); fprintf (stderr, "Attenzione: %s\n", cp); return 0; Semafori classici con i thread POSIX 10

Esempio errno con i semafori ret = sem_init(sem, pshared, value); if (ret == -1){ printf("sem_init: thread %d, %s: failed: %s\n", pthread_self(), msg, strerror(errno)); exit(1); Semafori classici con i thread POSIX 11

Creazione semaforo sem_t: tipo di dato associato al semaforo sem_t sem; Semafori classici con i thread POSIX 12

Inizializzazione (1 di 2) int int sem_init( sem_t *sem, int int pshared, unsigned int int value ) I semafori richiedono un inizializzazione esplicita da parte del programmatore sem_init serve per inizializzare il valore del contatore del semaforo specificato come primo parametro Semafori classici con i thread POSIX 13

Inizializzazione (2 di 2) sem_t *sem puntatore al semaforo da inizializzare, cioè l indirizzo dell oggetto semaforo sul quale operare int pshared flag che specifica se il semaforo è condiviso fra più processi se 1 il semaforo è condiviso tra processi se 0 il semaforo è privato del processo attualmente l'implementazione supporta solamente pshared = 0 unsigned int *value valore iniziale da assegnare al semaforo Valore di ritorno 0 in caso di successo, -1 altrimenti con la variabile errno settata a EINVAL se il semaforo supera il valore SEM_VALUE_MAX Semafori classici con i thread POSIX 14

Interfaccia wait (1 di 2) Consideriamo il semaforo come un intero, sul cui valore la funzione wait esegue un test Se il valore del semaforo è minore o uguale a zero (semaforo rosso), la wait si blocca, forzando un cambio di contesto a favore di un altro dei processi pronti che vivono nel sistema Se il test ha successo cioè se il semaforo presenta un valore maggiore od uguale ad 1 (semaforo verde), la wait decrementa tale valore e ritorna al chiamante, che può quindi procedere nella sua elaborazione. void wait (semaforo s) { s.count--; if (s.count < 0) <cambio di contesto>; Semafori classici con i thread POSIX 15

Interfaccia wait (2 di 2) Due varianti wait: bloccante (standard) trywait: non bloccante (utile per evitare deadlock) Semafori classici con i thread POSIX 16

wait int int sem_wait( sem_t *sem ) sem_t *sem puntatore al semaforo da decrementare Valore di ritorno sempre 0 Semafori classici con i thread POSIX 17

trywait int int sem_trywait( sem_t *sem ) sem_t *sem puntatore al semaforo da decrementare Valore di ritorno 0 in caso di successo -1 se il semaforo ha valore 0 setta la variabile errno a EAGAIN Semafori classici con i thread POSIX 18

Interfaccia signal L'operazione di signal incrementa il contatore del semaforo Se a seguito di tale azione il contatore risultasse ancora minore od uguale a zero, significherebbe che altri processi hanno iniziato la wait ma hanno trovato il semaforo rosso la signal sveglia quindi uno di questi; pertanto esiste una coda di processi bloccati per ciascun semaforo. void signal (semaforo s) { s.count++; if (s.count <= 0) <sveglia processo>; Semafori classici con i thread POSIX 19

sem_post int int sem_post( sem_t *sem ) sem_t *sem puntatore al semaforo da incrementare Valore di ritorno 0 in caso di successo -1 altrimenti con la variabile errno settata in base al tipo di errore sem_post restituisce EINVAL se il semaforo supera il valore SEM_VALUE_MAX dopo l incremento Semafori classici con i thread POSIX 20

sem_destroy int int sem_destroy( sem_t *sem ) sem_t *sem puntatore al semaforo da distruggere Valore di ritorno 0 in caso di successo -1 altrimenti con la variabile errno settata in base al tipo di errore sem_destroy restituisce EBUSY se almeno un thread è bloccato sul semaforo Semafori classici con i thread POSIX 21

sem_getvalue Serve per poter leggere il valore attuale del contatore del semaforo int int sem_getvalue( sem_t *sem, int int *sval ) sem_t *sem puntatore del semaforo di cui leggere il valore int *sval valore del semaforo Valore di ritorno sempre 0 Semafori classici con i thread POSIX 22

Esempio 7: lettori e scrittori (1 di 5) #include #include <stdio.h> <stdio.h> #include #include <pthread.h> <pthread.h> #include #include <semaphore.h> <semaphore.h> #define #define LUN LUN 20 20 #define #define CICLI CICLI 1 #define #define DELAY DELAY 100000 100000 struct struct { char char scritta[lun+1]; scritta[lun+1]; /* /* Variabili Variabili per per la la gestione gestione del del buffer buffer */ */ int int primo, primo, ultimo; ultimo; /* /* Variabili Variabili semaforiche semaforiche */ */ sem_t sem_t mutex, mutex, piene, piene, vuote; vuote; shared; shared; void void *scrittore1(void *); *); void void *scrittore2(void *); *); void void *lettore(void *lettore(void *); *); Continua Semafori classici con i thread POSIX 23

Esempio 7: lettori e scrittori (2 di 5) int int main(void) main(void) { pthread_t pthread_t s1tid, s1tid, s2tid, s2tid, ltid; ltid; int int res, res, i; i; shared.primo shared.primo = shared.ultimo shared.ultimo = 0; 0; sem_init(&shared.mutex, 0, 0, 1); 1); sem_init(&shared.piene, 0, 0, 0); 0); sem_init(&shared.vuote, 0, 0, LUN); LUN); pthread_create(&ltid, NULL, NULL, lettore, lettore, NULL); NULL); pthread_create(&s1tid, NULL, NULL, scrittore1, scrittore1, NULL); NULL); pthread_create(&s2tid, NULL, NULL, scrittore2, scrittore2, NULL); NULL); pthread_join(s1tid, NULL); NULL); pthread_join(s2tid, NULL); NULL); pthread_join(ltid, NULL); NULL); printf("e' printf("e' finito finito l'esperimento l'esperimento...\n");...\n"); Continua Semafori classici con i thread POSIX 24

Esempio 7: lettori e scrittori (3 di 5) void void *scrittore1(void *scrittore1(void *in) *in) { int int i, i, j, j, k; k; for for (i=0; (i=0; i<cicli; i<cicli; i++) i++) { for(k=0; for(k=0; k<lun; k<lun; k++) k++) { sem_wait(&shared.vuote); sem_wait(&shared.vuote); /* /* Controllo Controllo che che il il buffer buffer non non sia sia pieno pieno */ */ sem_wait(&shared.mutex); sem_wait(&shared.mutex); /* /* Acquisisco Acquisisco la la mutua mutua esclusione esclusione */ */ shared.scritta[shared.ultimo] shared.scritta[shared.ultimo] = '-'; '-'; /* /* Operazioni Operazioni sui sui dati dati */ */ shared.ultimo shared.ultimo = (shared.ultimo+1)%(lun); (shared.ultimo+1)%(lun); sem_post(&shared.mutex); sem_post(&shared.mutex); /* /* Libero Libero il il mutex mutex */ */ sem_post(&shared.piene); sem_post(&shared.piene); /* /* Segnalo Segnalo l aggiunta l aggiunta di di un un carattere carattere */ */ for(j=0; for(j=0; j<delay; j<delay; j++); j++); /* /*...... perdo perdo un un po po di di tempo tempo */ */ return return NULL; NULL; Continua Semafori classici con i thread POSIX 25

Esempio 7: lettori e scrittori (4 di 5) void void *scrittore2(void *scrittore2(void *in) *in) { int int i, i, j, j, k; k; for for (i=0; (i=0; i<cicli; i<cicli; i++) i++) { for(k=0; for(k=0; k<lun; k<lun; k++) k++) { sem_wait(&shared.vuote); sem_wait(&shared.vuote); /* /* Controllo Controllo che che il il buffer buffer non non sia sia pieno pieno */ */ sem_wait(&shared.mutex); sem_wait(&shared.mutex); /* /* Acquisisco Acquisisco la la mutua mutua esclusione esclusione */ */ shared.scritta[shared.ultimo] shared.scritta[shared.ultimo] = '+'; '+'; /* /* Operazioni Operazioni sui sui dati dati */ */ shared.ultimo shared.ultimo = (shared.ultimo+1)%(lun); (shared.ultimo+1)%(lun); sem_post(&shared.mutex); sem_post(&shared.mutex); /* /* Libero Libero il il mutex mutex */ */ sem_post(&shared.piene); sem_post(&shared.piene); /* /* Segnalo Segnalo l aggiunta l aggiunta di di un un carattere carattere */ */ for(j=0; for(j=0; j<delay; j<delay; j++); j++); /* /*...... perdo perdo un un po po di di tempo tempo */ */ return return NULL; NULL; Continua Semafori classici con i thread POSIX 26

Esempio 7: lettori e scrittori (5 di 5) void void *lettore(void *lettore(void *in) *in) { int int i, i, j, j, k; k; char char local[lun+1]; local[lun+1]; local[lun] local[lun] = 0; 0; /* /* Buffer Buffer locale locale */ */ for for (i=0; (i=0; i<2*cicli; i<2*cicli; i++) i++) { for(k=0; for(k=0; k<lun; k<lun; k++) k++) { sem_wait(&shared.piene); sem_wait(&shared.piene); /* /* Controllo Controllo che che il il buffer buffer non non sia sia vuoto vuoto */ */ sem_wait(&shared.mutex); sem_wait(&shared.mutex); /* /* Acquisisco Acquisisco la la mutua mutua esclusione esclusione */ */ local[k] local[k] = shared.scritta[shared.primo]; shared.scritta[shared.primo]; /* /* Operazioni Operazioni sui sui dati dati */ */ shared.primo shared.primo = (shared.primo+1)%(lun); (shared.primo+1)%(lun); sem_post(&shared.mutex); sem_post(&shared.mutex); /* /* Libero Libero il il mutex mutex */ */ sem_post(&shared.vuote); sem_post(&shared.vuote); /* /* Segnalo Segnalo che che ho ho letto letto un un carattere carattere */ */ for(j=0; for(j=0; j<delay; j<delay; j++); j++); /* /*...... perdo perdo un un pò pò di di tempo tempo */ */ printf("stringa printf("stringa = %s %s \n", \n", local); local); return return NULL; NULL; Semafori classici con i thread POSIX 27