Post on 21-Oct-2020
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!