Sommario
Il monitor è un costrutto sintattico che associa un insieme di operazioni a un struttura dati (risorsa) comune a più processi.
E’ stato introdotto per facilitare la programmazione strutturata di problemi in cui è necessario controllare l’assegnazione di una o più risorse tra più processi concorrenti mediante apposite discipline di gestione.
Il costrutto Monitor è sintatticamente del tutto analogo al costrutto di class ma, mentre quest’ultimo viene utilizzato per definire tipi di risorse dedicate…
..il monitor viene utilizzato per definire tipi di risorse condivise.
Si configura come un “tipo di dato astratto”, in cui
Lo scopo è quello di controllare l’assegnazione di una risorsa tra processi concorrenti in accordo a determinate politiche di gestione, secondo due livelli di controllo:
Separazione tra meccanismi e politiche!
Al fine di garantire che un solo processo alla volta abbia accesso alle variabili locali, si impone che
Al fine di garantire una disciplina che stabilisca l’ordine di accesso alla risorsa
La sospensione di un processo nel caso in cui la condizione non sia verificata, avviene utilizzando un nuovo tipo di variabile, detta variabile di tipo condition.
var_cond x;
x.wait;
…provoca la sospensione del processo fino a che un altro processo esegue x.signal;
NB: se non vi è alcun processo in attesa sulla variabile x, la signal non ha alcun effetto.
Sia P un processo sospeso su una variabile condition x e Q il processo che esegue la signal su tale variabile.
Proprietà del monitor violate!
Uno dei due processi deve essere pertanto sospeso.
Signal_and_wait prevede che il processo P risvegliato riprenda immediatamente l’esecuzione e che Q venga sospeso.
Q viene sospeso per evitare che possa modificare nuovamente la condizione di sincronizzazione.
E’ un caso particolare della signal_and_wait, denominata signal_and_urgent_wait.
Prevede che il processo Q abbia la priorità su ogni altro processo che intende entrare nel monitor.
Ciò si può ottenere sospendendo il processo Q su un’apposita coda (urgent_queue).
La semantica signal_and_wait privilegia il processo segnalato rispetto al segnalante.
Ciò implica che il segnalato, proseguendo la sua esecuzione, è certo di trovare vera la condizione per la quale è stato risvegliato.
Quindi lo schema tipico dell’invocazione di una wait è all’interno di un if:
if (!B) cond.wait();
//B è la condizione di sincronizz.
<accesso alla risorsa>
Signal_and_continue (detto anche wait and notify) privilegia il processo segnalante rispetto al segnalato. Il processo Q segnalante prosegue la sua esecuzione, mantenendo l’accesso esclusivo al monitor, dopo aver risvegliato P.
Q prosegue l’esecuzione dopo aver risvegliato P.
Il processo P segnalato viene trasferito alla coda associata all’ingresso del monitor.
Poiché in questa coda possono esistere altri processi, questi possono precedere l’esecuzione di P e quindi modificare il valore della condizione di sincronizzazione.
P dovrà pertanto testare nuovamente la condizione di sincronizzazione prima di proseguire.
Quindi, con una politica signal_and_continue lo schema tipico di uso della primitiva wait è all’interno di un while
while (!B) cond.wait()
<accesso alla risorsa>
La soluzione proposta può dar luogo ad inutili ripetute valutazioni della condizione di sincronizza., tuttavia elimina la complessità realizzativa insita nella politica signal_and_wait.
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.
Sono due le problematiche da risolvere:
Può essere semplicemente ottenuto associando ad ogni istanza del monitor un semaforo mutex inizializzato ad 1.
La richiesta di utilizzare il monitor equivale all’esecuzione di una wait(mutex);
Tale richiesta è nota con il termine di “ingresso al monitor”.
L’esigenza di garantire ai processi sospesi, non appena riattivati, la immediata ripresa della procedura interrotta, comporta la sospensione del processo che ha eseguito la signal sulla variabile condition.
Viene quindi introdotto un semaforo urgent (inizializzato a 0) sul quale i processi che hanno eseguito la signal si sospendono tramite una wait(urgent).
Prima di abbandonare il monitor è quindi necessario verificare che nessun processo sia in coda a tale semaforo.
Indicando con urgentcount un contatore (inizializzato a 0) del numero di processi sospesi sul semaforo urgent, l’uscita da una funzione del monitor sarà:
if (urgentcount>0)
signal(urgent);
else
signal(mutex);
CondVar
__________________________
-condsem=0: semaphore
-condcount=0: int
__________________________
+wait()
+signal()
Nell’ipotesi in cui la signal sia sempre eseguita come ultima operazione, è possibile una soluzione più semplice …
wait(){
condcount++;
signal(mutex);
wait(condsem);
condcount--;
}
signal(){
if (condcount>0)
signal(condsem);
else
signal(mutex);
}
1. Introduzione ai Sistemi Operativi
5. Scheduling nei sistemi mono-processore
6. Threads, SMP
8. Scheduling Multiprocessore e Real-Time
9. Gestione dei processi nei sistemi operativi Unix/Linux e Window...
10. Introduzione alla Programmazione Concorrente
11. Sincronizzazione nel modello ad ambiente globale
12. Problemi di cooperazione nel modello ad ambiente globale
14. Sincronizzazione nel modello ad ambiente locale
15. Deadlock
16. Programmazione Multithread
18. Memoria Virtuale
20. Il File System
21. Primitive di sincronizzazione nel kernel Linux
22. Esercitazione: System call per la gestione dei processi
23. Esercitazione: Inteprocess Communication e Shared Memory
24. Esercitazione: System Call per la gestione dei semafori in Linu...
25. Esercitazione: Problema dei Produttori e dei Consumatori
26. Posix Threads
W. Stallings, “Operating Systems : Internals and Design Principles (6th Edition) ”, Pearson Education (Par. 5.5)