capitolo 25 – lettori / scrittori

Transcript

capitolo 25 – lettori / scrittori
CAPITOLO 25 – LETTORI / SCRITTORI
Un altro problema classico che si incontra quando si tratta del tema della concorrenza e
sincronizzazione e che è utile sia a scopo didattico che come termine di paragone con i problemi di
progettazione è quello che viene chiamato problema dei lettori/scrittori.
Il problema ha la seguente definizione: c’è un’area di dati condivisa fra vari processi (questa può
essere un file, un blocco di memoria, o un banco di registri del processore) ed esistono dei processi
che concorrono per l’utilizzo dell’area: alcuni possono solo leggere i dati (lettori), altri possono solo
scrivere (scrittori).
Prima di analizzare il problema dei lettori/scrittori è bene evidenziare le differenze con altri due
classici problemi: il problema generale della mutua esclusione e il problema del
produttore/consumatore. Nel problema dei lettori/scrittori, i lettori non possono essere anche scrittori,
e gli scrittori non possono leggere. Se consideriamo come caso più generale quello in cui tutti i
processi possono sia leggere che scrivere è possibile risolvere il problema dichiarando la porzione
nella quale i processi accedono ai dati come sezioni critiche e quindi utilizzare la soluzione generale
per la mutua esclusione. La ragione per cui ci si pone nel problema particolare è che si possono
trovare soluzioni più efficienti rispetto alla soluzione generale che risulterebbe essere di una
lentezza inaccettabile in questo caso.
Se ad esempio si considera come area condivisa il catalogo di una biblioteca avremo gli utenti
normali che leggono il catalogo per cercare un libro e un paio di bibliotecari che si occupano di
aggiornare il catalogo. Applicando la soluzione generale, ogni accesso al catalogo sarebbe trattato
come sezione critica per cui un solo lettore per volta avrebbe accesso al catalogo causando così un
ritardo intollerabile. Allo stesso tempo è importante impedire agli scrittori di interferire tra loro, ed è
necessario impedire ai lettori di leggere mentre ci sono delle operazioni di scrittura in corso, per
evitare l’accesso ad informazioni non corrette.
È possibile considerare il problema del produttore/consumatore semplicemente come un caso
speciale del problema dei lettori/scrittori con un solo scrittore (il produttore) e un solo lettore (il
consumatore)? La risposta è no, perché il produttore non è solo uno scrittore, ma deve leggere i
puntatori della coda per stabilire dove mettere il prossimo elemento, e deve stabilire se il buffer è
pieno; analogamente il consumatore non è solo un lettore, perché deve modificare i puntatori della
coda per riflettere il fatto che un elemento è stato rimosso dal buffer.
Vincoli del problema
Verranno di seguito esaminate due soluzioni del problema, prima però si riassumono le condizioni
che devono essere soddisfatte:
1. più lettori possono leggere il file contemporaneamente.
2. solo uno scrittore alla volta può scrivere nel file.
3. se uno scrittore sta scrivendo nel file, nessun lettore può leggerlo
4. gli scrittori non possono leggere
5. i lettori non possono essere anche scrittori
Soluzione del problema con priorità ai processi lettori
Nella soluzione che usa i semafori vengono utilizzate le seguenti variabili e semafori:
1. la variabile globale numlettori è usata per tenere traccia del numero di lettori;
2. il semaforo x è usato per assicurarsi che numlettori sia aggiornata correttamente;
3. il semaforo wsem serve per garantire la mutua esclusione: i processi scrittori quando
accedono all’area condivisa utilizzano questo semaforo per impedire agli altri processi (sia
scrittori che lettori) di accedervi. Anche i processi lettori utilizzano il semaforo wsem, infatti
il primo lettore che tenta di leggere verifica che non ci siano scrittori nell’area condivisa
controllando il valore di wsem e lo setta per impedire ai processi scrittori di accedere all’area.
Altri processi lettori che intendono accedere all’area condivisa non si fermano su wsem ma
possono eseguire l’operazione di lettura.
Soluzione del problema usando i semafori: priorità ai lettori
procedure scrittore;
begin
repeat
wait(wsem);
SCRIVI_UNITÀ;
signal(wsem);
forever;
end;
procedure lettore;
begin
repeat
wait(x);
numlettori:=numlettori+1;
if numlettori=1 then
wait(wsem);
signal(x);
LEGGI_UNITÀ;
wait(x);
numlettori:=numlettori-1;
if numlettori=0 then
signal(wsem);
signal(x);
forever;
end;
Priorità agli scrittori
Nella soluzione precedente i lettori hanno la priorità: quando un lettore inizia ad accedere ai dati, i
lettori possono mantenere il controllo dell’area dati finchè c’è un lettore attivo, quindi gli scrittori
rischiano un’attesa perenne.
Di seguito viene mostrata una soluzione che impedisce a nuovi lettori di accedere ai dati se qualche
scrittore ha dichiarato di voler effettuare una scrittura; sono stati aggiungi i seguenti semafori e
variabili per gli scrittori:
1. un semaforo rsem che blocca i lettori quando c’è almeno uno scrittore che desidera accedere
ai dati;
2. una variabile numscrittori che controlla il numero di scrittori per gestire rsem;
3. un semaforo y che controlla l’aggiornamento di numscrittori;
4. un semaforo z che impedisce la formazione di una lunga coda di lettori sul semaforo rsem; in
questo modo i processi scrittori che intendono accedere all’area condivisa possono saltare la
coda. Con l’utilizzo del semaforo z ad un solo lettore è permesso di entrare nella coda di rsem
mentre tutti gli altri attendono su z prima di passare al semaforo rsem.
Analizziamo i due processi
procedure scrittore;
begin
repeat
wait(y);
il processo verifica il semaforo y,
se è positivo lo decrementa
e accede alla variabile numscrittori,
altrimenti attende
numscrittori:=numscrittori+1;
incrementa la variabile numscrittori
if numscrittori=1 then
se numscrittori ha valore 1 allora
wait(rsem); controlla il semaforo rsem e
se è positivo lo decrementa
(impedendo ai lettori di accedere
all’area condivisa)
signal(y);
rilascia la variabile numscrittori
incrementando il semaforo y
wait(wsem);
se wsem è positivo, lo decrementa
e accede all’area condivisa
(in questo modo impedisce ad altri scrittori
di accedere contemporaneamente)
SCRIVI_UNITA’;
signal(wsem);
wait(y);
Scrive
Incrementa il semaforo wsem
e rilascia l’area condivisa
il processo verifica il semaforo y,
se è positivo lo decrementa e accede
alla variabile numscrittori, altrimenti attende.
numscrittori:=numscrittori-1;Decrementa la variabile numscrittori
if numscrittori=0
then signal(rsem);
signal(y);
forever
end;
Se numscrittori è uguale a zero vuol dire
che non ci sono scrittori in attesa e incrementa il
semaforo rsem consentendo ai lettori
di leggere nell’area condivisa
Incrementa il semaforo y consentendo l’uso
da parte degli altri processi
della variabile numscrittori
procedure lettore;
begin
repeat
wait(z);
wait(rsem);
wait(x);
numlettori:=numlettori+1;
if numlettori=1 then
wait(wsem);
signal(x);
signal(rsem);
signal(z);
LEGGI_UNITA’;
wait(x);
numlettori:=numlettori-1;
controlla il semaforo z, se è positivo lo decrementa
e continua, altrimenti attende.
Controlla il semaforo rsem, se è positivo vuol dire
che non ci sono scrittori in attesa di leggere
controlla il semaforo x, se è positivo lo decrementa
e può accedere alla variabile numlettori.
Incrementa la variabile numlettori
Se numlettori è uguale a 1 allora
controlla se ci sono scrittori nell’area condivisa.
Attende che wsem gli dia il via libera
per procedere alla lettura
Incrementa i semafori x, rsem e z e consente
ad altri processi di effettuare i controlli
necessari per accedere all’area condivisa
Effettua la lettura dell’area condivisa
Controlla il semaforo x, se positivo può
accedere alla variabile numlettori
che andrà a decrementare.
if numlettori=0 then
Se numlettori è uguale a zero allora
signal(wsem); ncrementa il semaforo wsem in modo da
indicare che non ci sono lettori nell’area condivisa.
signal(x);
forever
end;
Incrementa il semaforo x concedendo ad altri
processi che ne fanno richiesta di
accedere alla variabile numlettori