Escolar Documentos
Profissional Documentos
Cultura Documentos
Possibilit di errori
Esempio: mutua esclusione scambio tra wait e signal: signal(mutex); <A>; wait(mutex); pi processi possono operare nella sezione critica. utilizzo erroneo di wait e signal: wait(mutex); <A>; wait(mutex); -> deadlock.
2
etc.
monitor tipo_risorsa { <dichiarazioni variabili locali>; <inizializzazione variabili locali>; public void op1 ( ) { <corpo della operazione op1 >; } ---------public void opn ( ) { <corpo della operazione opn>; } <eventuali operazioni non public> }
Le variabili locali sono accessibili solo entro il monitor. Le operazioni public (o entry) sono le sole operazioni che possono essere utilizzate dai processi per accedere alle variabili locali. L'accesso avviene in modo mutuamente esclusivo. Le variabili locali mantengono il loro valore tra successive esecuzioni delle operazioni del monitor (variabili permanenti). Le operazioni non dichiarate public non sono accessibili dallesterno. Sono usabili solo all'interno del monitor (dalle funzioni public e da quelle non public).
6
ris.opi(...);
chiamata di una generica operazione delloggetto ris.
Nel caso in cui la condizione non sia verificata, la sospensione del processo avviene utilizzando variabili di un nuovo tipo, detto condition (condizione). La condizione di sincronizzazione costituita da variabili locali al monitor e da variabili proprie del processo passate come parametri.
wait: Lesecuzione delloperazione wait(cond) sospende il processo, introducendolo nella coda individuata dalla variabile cond, e il monitor viene liberato. signal: Lesecuzione delloperazione signal(cond) rende attivo un processo in attesa nella coda individuata dalla variabile cond.
11
signal(cond);
Come conseguenza della signal entrambi i processi, quello segnalante Q e quello segnalato P, possono concettualmente proseguire la loro esecuzione. Possibili strategie: signal_ and_ wait. P riprende immediatamente lesecuzione ed il processo Q viene sospeso. signal_ and_ continue. Q prosegue la sua esecuzione mantenendo laccesso esclusivo al monitor, dopo aver risvegliato il processo .
12
Con la signal_ and_ wait si evita la possibilit che Q, proseguendo, possa modificare la condizione di sincronizzazione rendendola non pi vera per P. Q si sospende nella coda dei processi che attendono di usare il monitor (entry queue).
13
Signal&Continue
Signal&Wait
Signal&Wait si
14
call
monitor libero
E` una variante della signal_and_wait. signal_and_urgent_wait. Q ha la priorit rispetto agli altri processi che aspettano di entrare nel monitor. Viene quindi sospeso in una coda interna al monitor (urgent queue). Quando P ha terminato la sua esecuzione (o si nuovamente sospeso), trasferisce il controllo a Q senza liberare il monitor. condition queue wait monitor libero
entry queue esecuzione Signal&UrgentWait
Signal_and_urgent_wait
Signal&UrgentWait
urgent queue
P termina o si sospende
no
call
monitor libero
si
15
Un caso particolare della signal _and_urgent_wait (e della signal_and_wait) si ha quando essa corrisponde ad una istruzione return: signal_and_return. Il processo completa cio la sua operazione con il risveglio del processo segnalato. Cede ad esso il controllo del monitor senza rilasciare la mutua esclusione.
16
signal_and_continue
Il processo segnalato P viene trasferito dalla coda associata alla variabile condizione alla entry_queue e potr rientrare nel monitor una volta che Q labbia rilasciato. Poich altri processi possono entrare nel monitor prima di P, questi potrebbero modificare la condizione di sincronizzazione (lo stesso potrebbe fare Q). E pertanto necessario che quando P rientra nel monitor ritesti la condizione: while(!B) wait (cond); <accesso alla risorsa>
17
E possibile anche risvegliare tutti i processi sospesi sulla variabile condizione utilizzando la : signal_all che una variante della signal_and_continue. Tutti i processi risvegliati vengono messi nella entry_queue dalla quale, uno alla volta potranno rientrare nel monitor.
18
monitor buffer_circolare{ messaggio buffer[N]; int contatore=0; int testa=0; int coda=0; condition non_pieno; condition non_vuoto; /* procedure e funzioni entry: */ public void send(messaggio m){ /*proc. entry -> mutua esclusione*/ if (contatore==N) non_pieno.wait; buffer[coda]=m; coda=(coda + 1)%N; ++contatore; non_vuoto.signal; } public messaggio receive(){ /*proc. entry -> mutua esclusione*/ messaggio m; if (contatore == 0) non_vuoto.wait; m=buffer[testa]; testa=(testa + 1)%N; --contatore; non_pieno.signal; return m;} }/* fine monitor */
20
10
monitor allocatore { boolean occupato = false; condition libero; public void Richiesta() { if (occupato) libero.wait; occupato = true; } public void Rilascio() { occupato = false; libero.signal; } } allocatore A; /* istanza del tipo monitor*/ void processo() /*codice di un generico processo */ { A.Richiesta; <uso della risorsa>; A.Rilascio; }
22
11
Prologo di ogni operazione public: P(mutex); Epilogo di ogni operazione public: V(mutex);
wait(cond): { condcount++; V(mutex); P(condsem); P(mutex); }
Signal_and_ continue
Signal&Continue
condition queue
wait
call
entry queue
esecuzione
monitor libero
Signal&Continue
24
12
Signal_and_ wait
Prologo di ogni operazione public P(mutex); Epilogo di ogni operazione public V(mutex);
wait(cond): { condcount++; V(mutex); P(condsem); } signal(cond): { if (condcount>0) { condcount-- ; V(condsem); entry P(mutex); queue } call }
condition queue
Signal&Wait
wait
monitor libero
esecuzione
Signal&Wait
25
urgent: semaforo per la sospensione del processo segnalante (v.iniz. 0) urgentcount: contatore dei processi sospesi su urgent Prologo di ogni operazione: P(mutex); Epilogo di ogni operazione: if(urgentcount>0) wait(cond): { condcount++; if (urgentcount>0) V(urgent); else V(mutex); P(condsem); condcount-- ; }
call
Signal_and_urgent_wait
condition queue
Signal&UrgentWait
wait
entry queue monitor libero
esecuzione
Signal&UrgentWait
P termina o si sospende
urgent queue 26
13
Signal_and_return
Prologo di ogni operazione: P(mutex); Epilogo di ogni operazione: se la funzione non contiene signal allora : V(mutex) altrimenti signal(cond) (vedi sotto). wait(cond): { condcount++; V(mutex); P(condsem); condcount-- ; } signal(cond): { if (condcount>0) V(condsem); else V(mutex); }
27
14
num-lettori: il numero di processi lettori attivi sulla risorsa occupato: una variabile logica che indica se la risorsa occupata da uno scrittore (occupato=true) ok-lettura , ok-scrittura : due variabili condizione sulle quali si sospendono rispettivamente i processi lettori e scrittori
30
15
monitor lettori_scrittori { int num-lettori=0,occupato=0; condition ok_lettura,ok_scrittura; public void inizio_lettura() { if (occupato || ok_scrittura.queue) ok_lettura.wait; num_lettori++; ok_lettura.signal; } public void fine_lettura() { num_lettori-- ; if (num_lettori==0) ok_scrittura.signal; } public void inizio_scrittura() { if ((num_lettori!=0)|| occupato) ok_scrittura.wait; occupato=1; } /* continua...*/
31
/* ...continua */ public void fine_scrittura() { occupato=0; if (ok-lettura.queue) ok-lettura.signal; else ok-scrittura.signal; } }/* fine monitor */ lettori_scrittori LS; /* istanza del monitor*/ void lettore() /*codice di un generico lettore */ { LS.inizio_lettura(); <lettura>; LS.fine_lettura() } void scrittore() /*codice di un generico scrittore */ { LS.inizio_scrittura(); <scrittura>; LS.fine_scrittura() }
32
16
33
Algorimo scan
In un edificio a N piani, l'ascensore deve servire le richieste di utenti che competono per usare l'ascensore, con l'obiettivo di spostarsi a un piano diverso. L'ascensore puo` servire una richiesta alla volta. Movimento: l'ascensore si puo` spostare tra gli N piani [0,..N-1] nelle due direzioni: r dal basso verso l'alto (SU); r nella direzione opposta (GIU); L'algoritmo SCAN e` una possibile politica di scheduling delle richieste di uso dell'ascensore, che ha come obiettivo la minimizzazione del numero dei cambiamenti di direzione.
34
17
SCAN
Politica: r in ogni istante, all'ascensore e` associata una direzione corrente (SU, GIU) e una posizione corrente (piano associato alla prossima richiesta da servire). r ogni richiesta e` caratterizzata da una destinazione T (che individua il piano di destinazione richiesto dall'utente in attesa):
se l'ascensore sta salendo (direzione SU), verranno servite tutte le richieste con T raggiungibile in quella direzione (T> posizione corrente) se l'ascensore sta scendendo (direzione GIU), verranno servite tutte le richieste con T raggiungibile in quella direzione (T< posizione corrente).
r
le richieste sono servite secondo lordine di vicinanza alla richiesta corrente. Quando nella direzione scelta non ci sono pi richieste da servire, la direzione dell'ascensore viene invertita ed il procedimento ripetuto.
35
Modelliamo ogni utente dell'ascensore con un processo (thread) concorrente. Definiamo un monitor, il cui compito e` realizzare la politica di servizio mediante le due procedure entry: r Richiesta(T): viene invocata dai processi per ottenere la fermata dell'ascensore al piano T:
se l'ascensore occupato, la richiesta del processo viene accodata in funzione dello stato corrente del'ascensore (direzione e richiesta corrente) in una coda associata ad una direzione in modo da rispettare la politica.
r
Soluzione: monitor
Rilascio: viene invocata da ogni processo arrivato a destinazione per rilasciare l'ascensore:
se vi sono richieste in attesa sulla stessa direzione, verra` risvegliata la prima (la piu` vicina alla posizione corrente dell'ascensore); altrimenti, la direzione verra` invertita e verra` risvegliato il primo processo in attesa nella nuova direzione.
18
Monitor
Il monitor e` caratterizzato dalle seguenti variabili: r occupato: indica se l'ascensore sta servendo una richiesta; r direzione: indica la direzione corrente dell'ascensore (SU, GIU); r posizione: indica la destinazione corrente; r dir_SU, dir_GIU: condition associate alle due direzioni, sulle quali si sospenderanno i processi in attesa di servizio.
37
typedef int piano; typedef enum{SU,GIU}dir; monitor movimento_ascensore { piano posizione=0; /*inizialmente al piano terra..*/ boolean occupato=false; /* inizialmente libero..*/ dir direzione=SU; condition dir_SU,dir_GIU; public void Richiesta(piano dest) { if (occupato==true) if ((direzione==SU)&& (dest<=posizione)) dir_GIU.wait(dest); else dir_SU.wait(N-dest); occupato=true; posizione=dest; }
38
19
public void Rilascio { occupato=false; if (direzione==SU) if (dir_SU.queue) dir_SU.signal; else{ direzione=GIU; dir_GIU.signal; } else if (dir_GIU.queue) dir_GIU.signal; else{ direzione=SU; dir_SU.signal; }
} /* fine monitor*/
39
movimento_ascensore A; /* istanza del monitor*/ void Utente() /*codice di un generico utente */ { piano P; <assegnamento valore di P> A.Richiesta(P); <uso dell'ascensore>; A.Rilascio(); }
40
20