Sei sulla pagina 1di 10

Semafori

Sincronizzazione di processi e
thread (2)

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

Operating Systems and Distributed Systems

Operating Systems and Distributed Systems

Definizione di Dijkstra
Una variabile intera non negativa che pu essere
cambiata o testata da due funzioni atomiche
- verhoog (incrementa)
= up = signal =post

Tipi di Semafori
Binari:
Valori 0 e 1
Usati per la mutual exclusion (mutex)
Possono essere utilizzati per il signaling

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

- prolaag (probeer te verlagen = prova a decrementare)


= down = wait
P(s): [while(s == 0) {wait};
s = s - 1]

Operating Systems and Distributed Systems

Implementare i Semafori
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

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

Implementazione dei semafori


con busy wait (1)
typedef struct {
! int valore;
} semaforo;

void Wait(semaforo S) {
! S.valore--;
! while (S.valore < 0) {
! !
! }
}
void Signal(semaforo S) {
! S.valore++;
! }

pi lento
adatto per attese lunghe (I/O)
Operating Systems and Distributed Systems

Operating Systems and Distributed Systems

Implementazione dei semafori


con busy wait e interrupts (1)

Implementazione dei semafori


con sleep (2)

typedef struct {
! int valore;
} semaforo;

typedef struct {
! int valore;
! struct processo *p;
} semaforo;

void Wait(semaforo S) {
disableInterrupts();
! S.valore--;
! while (S.valore < 0) {
! !
enableInterrupts();
disableInterrupts();
! }
enableInterrupts();
}

void Wait(semaforo S) {
! S.valore--;
! if (S.valore < 0) {
! !
<accoda processo a S.p>;
! !
block();
! }
}

Operating Systems and Distributed Systems

KERNEL
mette il
processo in
stato di pronto

Operating Systems and Distributed Systems

Implementazione dei semafori:


commenti

Un esempio reale:
Semafori in MANTIS OS
void mos_sem_wait(mos_sem_t *s)
{
handle_t int_handle;

void mos_sem_post(mos_sem_t *s)


{
handle_t int_handle;
mos_thread_t *thread;

int_handle = mos_disable_ints();
int_handle = mos_disable_ints();
s->val--;
// Post a unit and wake-up the next waiting thread
s->val++;

// If no resources are available then we


wait in the queue
if(s->val < 0) {
mos_thread_t *id;
id = mos_thread_current();
mos_tlist_add(&s->q, id);
mos_thread_suspend_noints(int_handle);
} else

wait() e signal() considerate come vere e proprie


sezioni critiche

if((thread = mos_tlist_remove(&s->q)) != NULL) {


mos_thread_resume_noints_nodispatch(thread, int_handle);
mos_enable_ints(int_handle);
} else {
mos_enable_ints(int_handle);
}

mos_enable_ints(int_handle);
}

P(s)
Operating Systems and Distributed Systems

mette il
processo in
stato di attesa

void Signal(semaforo S) {
! S.valore++;
! if (S.valore <= 0) {
! !
<estrai un processo p da S.p>;
! !
wakeup(p);
! }
}

void Signal(semaforo S) {
disableInterrupts();
! S.valore++;
enableInterrupts();
! }

Le funzioni block() e wakeup() devono essere


fornite dal SO
Il criterio di estrazione usato nella wakeup() ,
generalmente, FIFO, ma pu non essere il solo
L'esecuzione di wait() e signal() atomica

puntatore alla lista


dei processi in attesa
di entrare nella
sezione critica

V(s)
Operating Systems and Distributed Systems

Sezione critica con semafori

Signaling con Semafori: Barriere


Sincronizzazione di pi processi
Attendono alla barriera finch tutti arrivano
Poi proseguono...

semaphore_t mutex = 1;
int var_condivisa;
void worker() {
while(1) {
Wait(mutex);
var_condivisa ++;
Signal(mutex);
}
}

A
B

A
B

Processi che arrivano


alla barriera

B e D alla
barriera

Tutti alla Barriera rilascia i


barriera
processi

14

Operating Systems and Distributed Systems

Operating Systems and Distributed Systems

Signaling con Semafori: Barriere


Usa un binary semaphore per segnalare un evento
Un thread attende un evento con Wait
Un thread segnala l evento con Signal

Signaling con Semafori:


sincr. Driver/Controller
Driver: segnala il controller con Signal(busy), e attende il
completamento delloperazione con Wait(done)
Controller: attende richieste con Wait(busy), e segnala il
completamento con Signal(done)

Questo crea una barriera fra i due Thread

Thread #1

Thread #2

...
...
Signal(ready1);
Wait(ready2);
...
...

...
...
Signal(ready2);
Wait(ready1);
...
...

Variabili Globali
semaphore ready1 = 0;
semaphore ready2 = 0;

Operating Systems and Distributed Systems

Device driver

Controller

...
...
Signal(busy);
Wait(done);
...
...

...
...
Wait(busy);
Signal(done);
...
...

Variabili Globali
semaphore busy = 0;
semaphore done = 0;

Operating Systems and Distributed Systems

Signaling con Semafori:


serializzazione
Sequenza di operazioni

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 lapertura: 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

Operating Systems and Distributed Systems

Semafori POSIX: anonimi


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 lapertura: sem_post() and sem_wait().
Distruzione: sem_destroy().
Operating Systems and Distributed Systems

Semafori POSIX
Prototipi 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);

Semafori POSIX
Interrogare il valore del semaforo
int sem_getvalue(sem_t *sem, int *valp);

esempio:
sem_wait(&sem_name);

! ! Se il valore <0, il processo si blocca;


un processo bloccato si risveglia (wake up) quando un altro processo
segnala con sem_post.
Per segnalare (incrementare il valore):
int sem_post(sem_t *sem);

Esempio:
sem_post(&sem_name);
Operating Systems and Distributed Systems

Semafori POSIX: esempio


#define NITER 1000000
int count = 0;
sem_t mymutex; //Declare the semaphore global (outside of any function)
void * ThreadAdd(void *); //function executed by threads
int main(int argc, char * argv[]){
pthread_t tid1, tid2;!
!
//Initialize the unnamed semaphore in the main function: initial value is set to 1.
// Note the second argument: passing zero denotes that the semaphore is shared between threads (and
// not processes).
!
sem_init(&mymutex, 0, 1);
!
pthread_create(&tid1, NULL, ThreadAdd, NULL);
pthread_create(&tid2, NULL, ThreadAdd, NULL);
pthread_join(tid1, NULL);!
/* wait for the thread 1 to finish */
pthread_join(tid2, NULL);
/* wait for the thread 2 to finish */
if (count < 2 * NITER) printf("\n BOOM! count is [%d], should be %d\n", count, 2*NITER);
else printf("\n OK! count is [%d]\n", count);
!
// destroys the semaphore; no threads should be waiting on the semaphore if its destruction is to succeed
!
sem_destroy(&mymutex);
pthread_exit(NULL);
}
void * ThreadAdd(void * a){
int i, tmp;
!
int value;
for(i = 0; i < NITER; i++){!
!
!
!
//entering the critical section: wait on semaphore
!
sem_wait(&mymutex);!
!
tmp = count;
/* copy the global count locally */
tmp = tmp+1;
/* increment the local copy */
count = tmp;
/* store the local value into the global count */
!
//exiting the critical section:
sem_post(&mymutex);!
!
}
}
Operating Systems and Distributed Systems

! ! il valore viene scritto allindirizzo puntato da valp


Esempio:
int value;
sem_getvalue(&sem_name, &value);
printf("Il valore e %d\n", value);

Distruzione semaforo:
int sem_destroy(sem_t *sem);

! ! funzione se nessun thread bloccato sul semaforo


Esempio:
sem_destroy(&sem_name);
Operating Systems and Distributed Systems

Semafori POSIX: esempio


Compile & run p_thraddsem.c!
Oppure provare (per MacOS) il
codice platform independent in
p_thraddsem2.c!

Operating Systems and Distributed Systems

Compile & run

p_sembarr.c!

Signaling con Semafori: Barriere

Il problema del bounded buffer o


del produttore/consumatore
Empty Pool

macbook-di-giuseppeboccignone:Lez15_ex2 Bebo$ ./p_sembarr


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

Producer

Consumer

Full Pool

main() reporting: tutti i 2 thread terminati

Operating Systems and Distributed Systems

Il problema del bounded buffer o


del produttore/consumatore

Operating Systems and Distributed Systems

Il problema del bounded buffer o


del produttore/consumatore
Istruzioni atomiche:

Variabili condivise

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

27

Operating Systems and Distributed Systems

const int n;
typedef Item;
Item buffer[n];
int in = 0, out = 0,
counter = 0;

Counter ++;
Counter --;

Produttore

Consumatore

Item pitm;
while (1) {

produce un item in pitm

while (counter == n)
;
buffer[in] = pitm;
in = (in+1) % n;
counter ++;
}

Item citm;
while (1) {
while (counter == 0)
;
citm = buffer[out];
out = (out+1) % n;
counter --;

consume l item in citm

28

Operating Systems and Distributed Systems

Produttore/consumatore con semafori

Produttore/consumatore con semafori


#define BSIZE 4
#define NUMITEMS 30
#define NUM_THREADS 2
pthread_t tid[NUM_THREADS];

//number of slots in the buffer


//max number of items
// 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;

29

Produttore/consumatore con semafori

30

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<NUMITEMS;i++) { // produce an item, one character from item[]
!
!
!
!
if (item[i] == '\0') break; // Quit if at end of string.
!
!
!
!
if (buffer.occupied >= 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);
}

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

32

Produttore/consumatore con semafori

Produttore - consumatore

void *consumer(void * parm)


{
!
char item;
!
int i;
!
!
printf("consumer started.\n");
!
!
for(i=0;i<NUMITEMS;i++){ // consume an item, one character from buffer
!
!
if (buffer.occupied <= 0) printf("consumer waiting.\n");
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
!
}

!
_sem_wait(&(buffer.more));!
//decrement full count
!
_sem_wait(&(buffer.mutex));!
//enter critical region
!
!
printf("consumer executing.\n");
!
!
item = buffer.buf[buffer.nextout++];//take item from buffer!
!
!
buffer.nextout %= BSIZE;
!
buffer.occupied--;
!
!
_sem_signal(&(buffer.mutex));!
//leave critical region
!
_sem_signal(&(buffer.less));!
//signals the producer and increments empty count
!
!
printf("%c\n",item);! !
//prints the item
!
}
printf("consumer exiting.\n");
pthread_exit(0);

Compile & run p_boundsem.c!

33

Lettori e scrittori

Operating Systems and Distributed Systems

Lettori e scrittori
Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader

Writer
Writer
Writer
Writer
Writer
Writer
Writer

Writers
Readers

Shared Resource

Operating Systems and Distributed Systems

Operating Systems and Distributed Systems

Lettori e scrittori

Lettori e scrittori

Writer
Writer
Writer
Writer
Writer
Writer
Writer

Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader

Writer
Writer
Writer
Writer
Writer
Writer

Reader
Reader
Reader
Reader
Reader
Reader
Reader
Reader

Writer
Shared Resource

Shared Resource

Operating Systems and Distributed Systems

Operating Systems and Distributed Systems

Lettori e scrittori

Compile & run p_rwexsem.c!

39