Monitory Jarosław Kuchta
Co to jest monitor Monitor to zebrane w jednej konstrukcji programowej zmienne i operacje na tych zmiennych. Część tych operacji jest udostępnianych na zewnątrz monitora. Tylko udostępnione operacje umożliwiają działanie na zmiennych. Wykonanie operacji monitora jest sekcją krytyczną wykonującego ją procesu. Wewnątrz monitorowanej operacji istnieje możliwość wstrzymywania i wznawiania procesów.
Szczegóły zmienna c typu condition umożliwia wstrzymywanie / wznawianie procesów posiada własną kolejkę procesów operacje: wait(c) powoduje wstrzymanie procesu wykonującego tę operację; proces jest wstawiany na koniec kolejki właściwej dla zmiennej c; monitor jest zwalniany signal(c) powoduje wznowienie wstrzymanego procesu; wznawiany jest pierwszy proces z kolejki właściwej dla zmiennej c; proces ten czeka, aż proces wywołujący tę operację zwolni monitor empty(c) funkcja sprawdzająca, czy kolejka właściwa dla zmiennej c nie jest pusta
Przechodzenie procesów przez monitor P M.P(1.0) kolejka wejściowa kolejka procesów wstrzymanych po signal void P(float x) wait (C); signal (C); Monitor M kolejka procesów oczekujących na C
Przykłady Wzajemne wykluczanie Producenci i konsumenci Czytelnicy i pisarze Pięciu filozofów
Wzajemne wykluczanie static class Wykluczanie: Monitor public static void Dostęp() Enter (this); // Działanie na zasobach Exit (this); class ProcesGłówny void Działaj() // własne sprawy Wykluczanie.Dostęp(); // własne sprawy
Producenci i konsumenci Monitor Bufor; Object Producenci = new Object(); Object Konsumenci = new Object(); const int N=10;y void Produkuj (Dane element) if (n == N) Bufor.Wait (Producenci); n = n + 1; bufor[ i] = element; i = (i+1) % N; Bufor.Signal (Konsumenci); Dane[] bufor = new Dane[N]; int n=0; int i = 0; int j = 0; void Konsumuj (out Dane element) if (n == 0) Bufor.Wait (Konsumenci); n = n 1; element = bufor [j]; j = (j+1) % N; Bufor.Signal (Producenci);
void Początek_Czytania() if (ile_pisze > 0) Wait (Czytelnicy); ile_czyta++; Czytelnicy i pisarze (z możliwością zagłodzenia pisarza) class Czytelnia: Monitor Object Czytelnicy = new Object(); Object Pisarze = new Object(); int ile_czyta = 0; int ile_pisze = 0; void Koniec_Czytania() ile_czyta--; if (ile_czyta == 0) Signal (Pisarze); void Początek_Pisania() if (ile_czyta + ile_pisze > 0) Wait (Pisarze); ile_pisze = 1; void Koniec_Pisania() ile_pisze = 0; if (!Empty(Pisarze) Signal (Pisarze) else do Signal (Czytelnicy) while (!Empty(Czytelnicy))
class Czytelnia: Monitor Object Czytelnicy = new Object(); Object Pisarze = new Object(); int ile_czyta = 0; int ile_pisze = 0; void Początek_Czytania() if (!Empty(Czytelnicy) ile_pisze > 0) Wait (Czytelnicy); ile_czyta++; void Koniec_Czytania() ile_czyta--; if (ile_czyta == 0) Signal (Pisarze); Czytelnicy i pisarze (rozwiązanie poprawne) void Początek_Pisania() if (ile_czyta + ile_pisze > 0) Wait (Pisarze); ile_pisze = 1; void Koniec_Pisania() ile_pisze = 0; if (!Empty(Pisarze) Signal (Pisarze) else do Signal (Czytelnicy) while (!Empty(Czytelnicy))
class Pałeczki: Monitor int [] wolne = new int[] 2, 2, 2, 2, 2; object [] Filozof = new object[5]; Pięciu filozofów (przymiarka pierwsza) void Biorę(int i) while (wolne [i] < 2) Wait (Filozof [i]); wolne [(i 1 ) % 5] = wolne [(i 1) % 5] - 1; wolne [(i+1) % 5] = wolne [(i+1) % 5] - 1; void Odkładam(int i) wolne [(i 1) % 5] = wolne [(i 1) % 5] + 1; wolne [(i+1) % 5] = wolne [(i+1) % 5] + 1; Signal (Filozof[(i 1) % 5]); Signal (Filozof[(i+1) % 5]);
class Pałeczki: Monitor int [] wolne = new int[] 2, 2, 2, 2, 2; object [] Filozof = new object[5]; Pięciu filozofów (przymiarka druga) void Biorę(int i) while (wolne [i] < 2) Wait (Filozof [i]); wolne [(i 1 ) % 5] = wolne [(i 1) % 5] - 1; wolne [(i+1) % 5] = wolne [(i+1) % 5] - 1; void Odkładam(int i) wolne [(i 1) % 5] = wolne [(i 1) % 5] - 1; wolne [(i+1) % 5] = wolne [(i+1) % 5] - 1; if (wolne[(i-1) % 5] == 2) Signal (Filozof[(i 1) % 5]); if (wolne[(i+1) % 5] == 2) Signal (Filozof[(i+1) % 5]);
Pięciu filozofów (rozwiązanie poprawne) class Pałeczki: Monitor bool [] zajęta = new bool[5]; object [] Pałeczka = new object[5]; object Lokaj = new object(); void Biorę(int i) if (ile_je == 4) Wait (Lokaj); ile_je ++; if (zajęta [i]) Wait (Pałeczka [i]); zajęta[ i] = true; if (zajęta[(i+1) % 5]) Wait (Pałeczka [(i+1) % 5]); zajęta[(i+1) % 5] = true; int ile_je = 0; void Odkładam(int i) zajęta [i] = false; Signal (Pałeczka[i]); zajęta [(i+1) % 5] = false; Signal (Pałeczka[(i+1) % 5]); ile_je --; Signal (Lokaj);
Implementacje Monitora Zmienne warunkowe z blokowaniem Zmienne warunkowe bez blokowania Monitory z niejawnym warunkiem
Zmienne warunkowe z blokowaniem (monitor Hoara) wątek powiadamiający jest blokowany do czasu, aż powiadomiony wątek oczekujący nie opuści monitora lub nie zatrzyma się w ponownym oczekiwaniu na warunek. dwie główne kolejki wątków: e - kolejka wejściowa s - kolejka wątków powiadamiających każda zmienna warunkowa c posiada własną kolejkę c.q wątków oczekujących na spełnienie warunku. a.q b.q enter e s wait(a) signal wait(b) exit
Zmienne warunkowe bez blokowania (monitor Massy) operacja signal nie powoduje opuszczenia monitora wątek oczekujący jest przenoszony do kolejki e, aby zaczekać, aż wątek powiadamiający zakończy swoje zadanie kolejka s jest niepotrzebna operacja signal nazywa się teraz notify a.q b.q enter notified e notified wait(b) wait(a) exit
Monitory z niejawnym warunkiem W języku Java każdy obiekt może stać się monitorem metody wykluczane są oznaczone słowem kluczowym synchronized. monitor ma kolejkę wejściową i pojedynczą kolejkę wszystkie operacje dotyczą tej jednej kolejki (najwyżej jeden warunek) q enter e notified wait exit
Klasa Monitor w C# (1) public static class Monitor public static void Enter (Object obj) wejście do monitora public static bool TryEnter (Object obj) public static bool TryEnter (Object obj, int millisecondstimeout) public static bool TryEnter (Object obj, TimeSpan timeout) public static void Exit (Object obj) wyjście z monitora
Klasa Monitor w C# (2) public static bool Wait (Object obj) oczekiwanie public static bool Wait (Object obj, int millisecondstimeout) public static bool Wait(Object obj, TimeSpan timeout) public static bool Wait (Object obj, int millisecondstimeout, bool exitcontext) public static bool Wait( Object obj, TimeSpan timeout, bool exitcontext ) public static void Pulse (Object obj) sygnalizacja public static void PulseAll (Object obj) sygnalizacja do wszystkich