Monitor Costrutto sintattico che associa un insieme di procedure ad una struttura dati comune a più processi. Il compilatore può verificare che esse siano le sole operazioni permesse su quella struttura. Le procedure sono mutuamente esclusive:un solo processo per volta può essere attivo nel monitor. Le procedure entry sono le sole operazioni che possono essere utilizzate dai processi per accedere alle variabili comuni. Le variabili comuni mantengono il loro valore tra successive esecuzioni delle procedure del monitor (variabili permanenti). Sono accessibili solo entro il monitor. Le variabili locali definiscono lo stato della risorsa. Le procedure non dichiarate entry non sono accessibili dall esterno. Sono usabili solo dalle procedure entry. Il codice per l inizializzazione delle variabili entry viene eseguito una sola volta prima dell esecuzione di qualunque procedura. type < nome del tipo> = monitor; <dichiarazioni variabili locali>; procedure entry <nome> ( );..; --- procedure entry <nome>; ( );..; --- procedure <nome>( );..; <var nome-istanza>:<nome-monitor>; crea un particolare oggetto monitor, cioè una struttura dati organizzata secondo quanto indicato nella dichiarazione dei dati locali. <nome-istanza>.< nome procedura >( ); chiamata di una particolare procedura di un oggetto monitor da parte di un processo. <statement iniziale> 1
Scopo del monitor è controllare l assegnazione di una risorsa tra processi concorrenti in accordo a determinate politiche di gestione. L assegnazione avviene secondo due livelli di controllo: Il primo garantisce che un solo processo alla volta possa aver accesso alle variabili comuni del monitor. Ciò è ottenuto garanto che le procedure entry siano eseguite in modo mutuamente esclusivo (eventuale sospensione dei processi). Il secondo controlla l ordine con il quale i processi hanno accesso alla risorsa. La procedura chiamata verifica il soddisfacimento di una condizione logica che assicura l ordinamento (eventuale sospensione del processo e liberazione del monitor). Variabili tipo condizione Ogni variabile di tipo condizione rappresenta una coda nella quale i processi si sospono. Esistono tante variabili condizione quante sono le condizioni per cui un processo può essere ritardato. Le procedure del monitor agiscono su tali variabili mediante le operazioni: cond.wait cond.signal. L esecuzione dell operazione cond.wait sospe il processo e lo introduce nella coda individuata dalla variabile cond. L esecuzione dell operazione cond.signal re attivo un processo in attesa nella coda individuata dalla variabile cond. La condizione di sincronizzazione è costituita da variabili locali al monitor e da variabili proprie del processo passate come parametri. La sospensione del processo, nel caso in cui la condizione non sia verificata, avviene utilizzando variabili di un nuovo tipo, detto condition (condizione). Come conseguenza della signal entrambi i processi, quello segnalante P e quello segnalato Q, possono concettualmente proseguire la loro esecuzione. Esistono due possibilità : Signal and wait. P atte che Q abbandoni il monitor, o atte per un altra condizione Signal and continue. Q atte che P abbandoni il monitor, o atte per un altra condizione. 2
Signal and continue presenta l inconveniente che quando Q ripre l esecuzione la condizione logica per la quale stava atto potrebbe non essere più vera (modificata da P). Signal and wait assicura che P riprerà la sua esecuzione quando Q avrà completato la sua esecuzione, o si sarà nuovamente sospeso. Il monitor verrà liberato solo quando non vi saranno al suo interno processi in grado di completare l esecuzione. Compromesso: quando P esegue la signal abbandona immediatamente il monitor (signal eseguita come ultima istruzione della procedura.) procedure entry receive(x:messaggio); if cont=0 then non-vuoto.wait; x := buffer[testa]; testa := (testa+1)mod N; cont := cont -1; non-pieno.signal; cont := 0; testa := 0; coda := 0; (inizializzazione) var a, b : messaggio; var B, D : mailbox; (istanze del tipo monitor) B.s(a); B.receive(b) (chiamate delle procedure del monitor B da parte dei processi). Esempio: monitor come gestore di risorse (mailbox) type mailbox = monitor; var buffer : array [0 N-1] of message; testa, coda : 0...N-1; cont : 0 N; non-pieno, non-vuoto : condition; procedure entry s (x:messaggio); if cont=n then non-pieno.wait; buffer[coda] := x; coda := (coda+1)mod N; cont := cont +1; non-vuoto.signal; ESEMPIO: monitor con allocatore di risorse type allocatore = monitor; var occupato : boolean; libero : condition; procedure entry Richiesta; if occupato then libero.wait; occupato := true; procedure entry Rilascio; occupato := false; libero.signal; occupato := false 3
var alloc : allocatore (istanza del tipo monitor); /codice eseguito da un processo/ alloc.richiesta; <uso della risorsa>; alloc.rilascio; Il compilatore inserisce un prologo ed un epilogo all inizio ed all uscita da ogni procedure entry: prologo:wait(mutex) epilogo: if urgentcount > 0 then signal (urgent); else signal (mutex); Implementazione del monitor tramite semafori Il compilatore assegna ad ogni istanza di un monitor: un semaforo mutex inizializzato a 1 per la mutua esclusione delle procedure del monitor; un semaforo urgent inizializzato a 0 per effettuare la preemption dei processi segnalanti; un contatore urgentcount inizializzato a 0 per conteggiare in ogni istante i precedenti processi; per ogni variabile cond di tipo condition un semaforo condsem inizializzato a 0 ed un contatore condcount inizializzato a 0 per implementare cond.wait e cond.signal Il compilatore traduce le operazioni cond.wait e cond.signal nel seguente modo: cond.wait cond.signal condcount := condcount + 1; urgentcount := urgentcount + 1; if urgentcount > 0 then signal (urgent) if condcount > 0 then else signal (mutex) signal(condsem) wait(condsem); wait(urgent); condcount := condcount 1; urgentcount := urgentcount 1; condsem: semaforo associato a ciascuna variabile condizione (v.i. = 0) condcount: contatore associato a ciascuna variabile condizione (v.i. = 0) 4
cond.signal come ultima operazione delle procedure Non c è più necessità del semaforo urgent e del contatore urgentcount, per cui: prologo: epilogo: cond.wait: wait(mutex); signal(mutex); se la procedura non contiene cond.signal condcount := condcount + 1; signal (mutex); wait (condsem); condcount := condcount 1; Modifiche al monitor Sospensione con indicazione della priorità cond.wait (priorità) Variabili condizione intese come code monoprocesso. Il programmatore ha il controllo completo sulla scelta del processo da risvegliare. Funzioni primitive su variabili di tipo condizione: cond.queue operazione che verifica la presenza nella coda cond di almeno un processo sospeso Esempio: if cond.queue then cond.signal: if condcount > 0 then signal (condsem) else signal (mutex); La cond.signal rappresenta anche l epilogo della procedura Chiamate innestate a procedure di monitor Durante l esecuzione della procedura A1 del monitor A viene chiamata la procedura B1 del monitor B e durante l esecuzione di tale procedura il processo viene sospeso sulla variabile condizione X. Viene rilasciata la mutua esclusione per il monitor B, mentre il monitor A rimane occupato. Se la procedura B2 di B, a cui è demandato il compito di riattivare il processo, viene richiamata solo attraverso la procedura A2 di A, si ha una situazione di blocco critico Questa soluzione è imposta da un problema di congruenza dei dati; non esso terminata A1, se il monitor A viene liberato un nuovo processo può trovare la struttura dei dati del monitor non consistente. 5
CHIAMATE INNESTATE A MONITOR Monitor A <dati> procedure entry A1;.. B.B1 ; procedure entry A2; Monitor B <dati> procedure entry B1; X.wait ; procedure entry B2; 6