Semafori Sincronizzazione di processi e thread...

10
Operating Systems and Distributed Systems Sincronizzazione di processi e thread (2) Operating Systems and Distributed Systems Semafori Operating Systems and Distributed Systems Meccanismi di sincronizzazione Operating Systems and Distributed Systems Semafori di Dijkstra Inventati nel 1960s Meccanismo concettuale: nessuna implementazione specificata Meccanismo di sincronizzazione di base nei sistemi operativi

Transcript of Semafori Sincronizzazione di processi e thread...

  • Operating Systems and Distributed Systems

    Sincronizzazione di processi e thread (2)

    Operating Systems and Distributed Systems

    Semafori

    Operating Systems and Distributed Systems

    Meccanismi di sincronizzazione

    Operating Systems and Distributed Systems

    Semafori di Dijkstra

    • Inventati nel 1960s

    • Meccanismo concettuale: nessuna implementazione specificata

    • Meccanismo di sincronizzazione di base nei sistemi operativi

  • • Una variabile intera non negativa che può essere cambiata o testata da due funzioni atomiche

    - verhoog (incrementa)

    = up = signal =post

    - prolaag (probeer te verlagen = prova a decrementare) = down = wait

    Operating Systems and Distributed Systems

    Definizione di Dijkstra

    V(s): [s = s + 1]

    P(s): [while(s == 0) {wait};

    s = s - 1]

    Operating Systems and Distributed Systems

    Tipi di Semafori

    • Binari:– Valori 0 e 1

    – Usati per la mutual exclusion (mutex)

    – Possono essere utilizzati per il signaling

    • Semafori contatore (Counting Semaphores):– Prendono un qualsiasi valore >0

    – Contano risorse e bloccano i resource consumers quando le risorse sono esaurite

    Operating Systems and Distributed Systems

    • Due modalità distinte:– busy waiting (spinlock): la CPU controlla

    attivamente il verificarsi della condizione di accesso alla sezione critica

    • scalabile, veloce

    • CPU-intensive

    • adatto per attese brevi (accesso a memoria)

    – sleep (mutex,semaforo): il processo viene messo in attesa (sleep) che si verifichi la condizione di accesso alla sezione critica

    • più lento

    • adatto per attese lunghe (I/O)

    Implementare i Semafori

    typedef struct {

    ! int valore;} semaforo;

    void Wait(semaforo S) {! S.valore--;

    ! while (S.valore < 0) {! !

    ! }}

    void Signal(semaforo S) {

    ! S.valore++;! }

    Operating Systems and Distributed Systems

    Implementazione dei semafori con busy wait (1)

  • typedef struct {

    ! int valore;} semaforo;

    void Wait(semaforo S) { disableInterrupts();

    ! S.valore--;! while (S.valore < 0) {

    ! ! enableInterrupts(); disableInterrupts();

    ! } enableInterrupts();

    }

    void Signal(semaforo S) { disableInterrupts();

    ! S.valore++; enableInterrupts();

    ! }

    Operating Systems and Distributed Systems

    Implementazione dei semafori con busy wait e interrupts (1)

    typedef struct {

    ! int valore;! struct processo *p;

    } semaforo;

    void Wait(semaforo S) {

    ! S.valore--;! if (S.valore < 0) {

    ! ! ;! ! block();

    ! }}

    void Signal(semaforo S) {

    ! S.valore++;! if (S.valore

  • Operating Systems and Distributed Systems

    Sezione critica con semafori

    semaphore_t mutex = 1;

    int var_condivisa;

    void worker() {

    while(1) {

    Wait(mutex);

    var_condivisa ++;

    Signal(mutex);

    }

    }

    Operating Systems and Distributed Systems14

    Signaling con Semafori: Barriere

    • Sincronizzazione di più processi

    • Attendono alla “barriera” finchè tutti arrivano

    • Poi proseguono...

    B e D allabarriera

    A

    B

    C

    D

    Tutti allabarriera

    A

    B

    C

    D

    Barriera rilascia iprocessi

    A

    B

    C

    D

    Processi che arrivanoalla barriera

    A

    B

    C

    D

    Operating Systems and Distributed Systems

    • Usa un binary semaphore per segnalare un evento

    – Un thread attende un evento con Wait

    – Un thread segnala l’ evento con Signal

    • Questo crea una barriera fra i due Thread

    . . .

    . . .

    Signal(ready1);

    Wait(ready2);

    . . .

    . . .

    Thread #1

    . . .

    . . .

    Signal(ready2);

    Wait(ready1);

    . . .

    . . .

    Thread #2

    semaphore ready1 = 0;

    semaphore ready2 = 0;

    Variabili Globali

    Signaling con Semafori: Barriere

    Operating Systems and Distributed Systems

    Signaling con Semafori: sincr. Driver/Controller

    • Driver: segnala il controller con Signal(busy), e attende il completamento dell’operazione con Wait(done)

    • Controller: attende richieste con Wait(busy), e segnala il completamento con Signal(done)

    . . .

    . . .

    Signal(busy);

    Wait(done);

    . . .

    . . .

    Device driver

    . . .

    . . .

    Wait(busy);

    Signal(done);

    . . .

    . . .

    Controller

    semaphore busy = 0;

    semaphore done = 0;

    Variabili Globali

  • Operating Systems and Distributed Systems

    • Sequenza di operazioni

    Signaling con Semafori: serializzazione

    Operating Systems and Distributed Systems

    Semafori POSIX: con nome• Due forme:

    – named semaphores – unnamed semaphores.

    • Named semaphore identificato da un nome.

    – Due processi lo possono utilizzare passando uno stesso nome a sem_open().

    • crea o apre un named semaphore esistente.

    – Dopo l’apertura: sem_post() and sem_wait().

    – Chiusura: sem_close()

    – Distruzione( quando i processi sono terminati) sem_unlink()

    • I named semaphores POSIX hanno persistenza nel kernel: se non sono rimossi da sem_unlink(), un semaforo esiste fino allo shut down del sistema.

    Operating Systems and Distributed Systems

    • Due forme:

    – named semaphores

    – unnamed semaphores.

    • Un unnamed semaphore è anonimo.

    • Collocato in una regione di memoria condivisa fra più threads ( thread-shared semaphore) o più processi (process-shared semaphore).

    – Thread-shared semaphore: esempio, una variabile globale.

    – Process-shared semaphore: esempio shared memory region (e.g., in System V shared memory segment creato con semget(), oppure un shared memory object POSIX ottenuto mediante shm_open()).

    • Prima di usarlo: sem_init().

    • Dopo l’apertura: sem_post() and sem_wait().

    • Distruzione: sem_destroy().

    Semafori POSIX: anonimiPrototipi definiti in semaphore.h.

    Dichiarazione:

    sem_t sem_name;

    Inizializzazione:

    int sem_init(sem_t *sem,

    int pshared,

    unsigned int value);

    !•!sem puntatore al semaforo

    !•!pshared =1 se shared con processi fork()ed.

    !•!value valore iniziale del semaforo (1 per sem binari)

    Esempio:

    sem_init(&sem_name, 0, 10);Operating Systems and Distributed Systems

    Semafori POSIX

  • Attesa su semaforo: int sem_wait(sem_t *sem);

    esempio: sem_wait(&sem_name);

    ! •! Se il valore è

  • macbook-di-giuseppe-boccignone:Lez15_ex2 Bebo$ ./p_sembarr

    Thread 1 qui, prima della barriera.Thread 2 qui, prima della barrieraThread 2 dopo la barriera.Thread 1 dopo la barriera.

    main() reporting: tutti i 2 thread terminati

    Operating Systems and Distributed Systems

    Com

    pile &

    run

    p_sembarr.c!

    Signaling con Semafori: Barriere

    Operating Systems and Distributed Systems

    Producer Consumer

    Empty Pool

    Full Pool

    Il problema del bounded buffer o del produttore/consumatore

    Operating Systems and Distributed Systems27

    • Produttore: mette items in un bounded buffer condiviso

    • Consumatore: preleva items dal bounded buffer

    • If buffer==VUOTO– il consumatore non può prelevare

    • If buffer== PIENO– il produttore non può inserire

    Il problema del bounded buffer o del produttore/consumatore

    Operating Systems and Distributed Systems28

    Variabili condiviseconst int n;

    typedef … Item;

    Item buffer[n];

    int in = 0, out = 0,

    counter = 0;

    Istruzioni atomiche:

    Counter ++;

    Counter --;

    ConsumatoreItem citm;while (1) { while (counter == 0) ; citm = buffer[out]; out = (out+1) % n; counter --; … consume l’ item in citm …}

    ProduttoreItem pitm;while (1) { … produce un item in pitm … while (counter == n) ; buffer[in] = pitm; in = (in+1) % n; counter ++;}

    Il problema del bounded buffer o del produttore/consumatore

  • 29

    Produttore/consumatore con semafori

    #define BSIZE 4 //number of slots in the buffer

    #define NUMITEMS 30 //max number of items

    #define NUM_THREADS 2

    pthread_t tid[NUM_THREADS]; // array of thread IDs

    typedef struct {

    ! char buf[BSIZE];

    ! int occupied;

    ! int nextin, nextout;

    #ifdef __APPLE__

    ! semaphore_t mutex ;//control access to critical region

    ! semaphore_t more ; //counts full buffer slots

    ! semaphore_t less ; //counts empty buffer slots

    #else

    ! sem_t mutex;//control access to critical region

    ! sem_t more; //counts full buffer slots

    ! sem_t less; //counts empty buffer slots

    #endif

    !

    } buffer_t;

    buffer_t buffer;

    30

    Produttore/consumatore con semafori

    int main( int argc, char *argv[] )

    {

    ! int i;

    !

    ! _sem_create(&(buffer.mutex), 1);

    ! _sem_create(&(buffer.more), 0);

    ! _sem_create(&(buffer.less), BSIZE);

    !

    ! pthread_create(&tid[1], NULL, consumer, NULL);

    ! pthread_create(&tid[0], NULL, producer, NULL);

    ! for ( i = 0; i < NUM_THREADS; i++)

    ! ! pthread_join(tid[i], NULL);

    !

    ! printf("\nmain() reporting that all %d threads have terminated\n", i);

    !

    ! _sem_destroy(&(buffer.mutex));

    ! _sem_destroy(&(buffer.more));

    ! _sem_destroy(&(buffer.less));

    ! return 0;

    !

    } /* main */

    31

    Produttore/consumatore con semafori

    void *producer(void * parm)

    {

    ! char item[NUMITEMS]="E’ UN MONDO PICCOLO, DOPO TUTTO."; // items to be put in buffer

    ! int i;

    !

    ! printf("producer started.\n");

    !

    ! for(i=0;i= BSIZE) printf("producer waiting.\n");

    ! !

    _sem_wait(&(buffer.less));! //decrement empty count

    ! ! _sem_wait(&(buffer.mutex));! //enter critical region

    ! ! printf("producer executing.\n");

    ! !

    ! ! buffer.buf[buffer.nextin++] = item[i];//put new item in buffer

    ! ! buffer.nextin %= BSIZE;

    ! ! buffer.occupied++;! ! //items in buffer

    ! !

    ! ! _sem_signal(&(buffer.mutex));! //leave critical region

    ! ! _sem_signal(&(buffer.more));! //signals the consumer and increments full count

    }

    ! printf("producer exiting.\n");

    ! pthread_exit(0);

    }

    32

    Produttore/consumatore con semafori

  • void *consumer(void * parm)

    {

    ! char item;

    ! int i;

    !

    ! printf("consumer started.\n");

    !

    ! for(i=0;i

  • Operating Systems and Distributed Systems

    Reader

    Shared Resource

    ReaderReader

    ReaderReader

    ReaderReader

    Reader

    WriterWriter

    WriterWriter

    WriterWriter

    Writer

    Lettori e scrittori

    Operating Systems and Distributed Systems

    Reader

    Shared Resource

    ReaderReader

    ReaderReader

    ReaderReader

    Reader

    WriterWriter

    WriterWriter

    WriterWriter

    Writer

    Lettori e scrittori

    39

    Lettori e scrittori

    Compile & run p_rwexsem.c!