# Monitor Un **monitor** e' una combinazione di ADT (abstract data type, *tipo astratto*) e **mutua esclusione**. *(vedi slides per definizione)* * I monitor sono strutture dati che implementano operazioni mutualmente esclusive. ## Implementazione ``` monitor stack { . . public push() public pop() . .etc } ``` Un monitor e' uno **stack**. *(slides per implementazione classica)* ### Esempio * La definizione di monitor definisce un tipo *alpha*, secondo la definizione classica. * Il tipo definito puo' essere instanzializzato: ``` alpha x ``` * Le operazioni generiche e **pubbliche** definite dal monitor sono chiamate con **dot notation**: ``` x.op_i() ``` **Tutte le operazioni implementate dal monitor sono mutualmente esclusive**, permettendo quindi una semplificazione e sicurezza maggiore nella scrittura di programmi concorrenti. **NOTA**: Il runtime support del linguaggio, che opera a livello kernel, usa comunque primitive semaforiche. L'utilizzo e' pero' astratto dal costrutto monitor. ## Variabili tipo condizione Sono variabili che si possono usare solo all'interno del monitor. In genere, **ogni condition e' implementata tramite una coda**, di solito FIFO. Le procedure dei monitor agiscono sulle variabili condizione con le operazioni: * wait(cond) <- sospende il processo in ogni caso e lo introduce nella coda individuata da cond * signal(cond) <- rende attivo un processo in attesa nella coda individuata da cond **NOTA**: wait e signal **non sono** equivalenti a P,V per i semafori, in quanto gestiscono automaticamente le code e non permettono di testare condizioni (*if(cond)...* va utilizzato prima di wait). *(slides per esempio)* Le variabili condizione possono essere utilizzate anche come semafori privati (N variabili condizione per N processi). ### Signal: realizzazione semantica Signal non e' in grado di discriminare tra processi bloccati. Quindi bisogna discriminare, tra due processi, quale debba proseguire nella SC (processo *svegliante* o processo *svegliato*). **Dipende dall'implementazione del singolo linguaggio**. Java, ad esempio, da la precedenza a un processo svegliante. Questo implica l'utilizzo di un while loop per svegliare tutta la pool di processi in coda, che pero' non e' starvation free. #### Java: Signal and continue Quando un processo viene svegliato da un altro, viene rimesso in coda, mentre il processo svegliante puo' continuare nella SC. Il processo svegliato quindi potrebbe ritrovarsi alla fine della coda. **Problema starvation svegliato** #### Signal and wait Opposto del signal and continue: il processo svegliato prende il posto dello svegliante, e lo svegliante va in fondo alla coda. **Problema starvation svegliante** #### Signal and urgent wait Signal and wait, ma il processo svegliante acquisisce la prima posizione nella coda (**urgent queue**). Questo e' l'approccio piu' *fair* rispetto a tutti i processi. *(slides per esempio allocatore)* **In una semantica SAUW, non ha senso utilizzare primitive signalAll**, in quanto violano il principio della mutua esclusione. ## Comparison: Monitor e Semafori Qual'e' il piu' *potente* (inteso: che risolve la piu' vasta gamma di problemi) tra monitor e semafori? * Sono **equivalenti**, in quanto con i semafori e' possibile implementare i monitor, e con i monitor e' possibile implementare i semafori. Non sono quindi piu' potenti dei semafori, sono solo un'astrazione di essi. *(vedi slides per dimostrazione di realizzazione)* ## Operazioni aggiuntive su variabili condizione * **wait(cond,p)**: wait con indicazione della priorita', che e' data come numerica, in ordine di solito decrescente. (priorita' 0 = massima). Il linguaggio implementa quindi una *priority queue*. * **empty(cond)**: true se la coda e' vuota, false se ci sono processi in attesa * **signalAll(cond)**: rende attivi tutti i processi in coda, ma si puo' utilizzare **solo con signal and continue**. ## Esempi ### Shortest-job-next: allocazione di risorse ``` monitor allocatore { bool occupata = false; condition non_occ; public void richiesta (int tempo) { if (occupata) { wait (non_occ, tempo); occupata = true; } } } ``` *(altri esempi su slides, disco a teste mobili, lettori / scrittori con monitor)* #### Monitor: Lettori / scrittori - Prova di correttezza La prova di correttezza di un monitor si ottiene tramite gli **invarianti di monitor**, dimostrate valide per induzione: * sono vere al momento dell'inizializzazione del monitor * sono vere all'uscita di esecuzione della chiamata al monitor L'invariante da dimostrare e' il seguente: siano: * R - numero di processi in lettura * W - numero di processi in scrittura ``` (R>0 => W=0) and (W <= 1) and (W = 1 => R = 0) ``` * Facilmente dimostrabile e' il seguente gruppo di invarianti: ``` R = num_lett W = num_scritt R >= 0 W >= 0 ``` ##### Dimostrazione * All'inizio, l'invariante in tesi e' chiaramente vero. * Supposto vero all'inizio di ciascuna delle 4 procedure di monitor, e' vero anche alla fine. *(vedi slides per casi specifici)*