Semafory i monitory
Transkrypt
Semafory i monitory
Wady mechanizmów niskopoziomowych Ingerencja w kod systemu operacyjnego (przerwania) Programowanie na niski poziomie (instrukcje specjalne) Trudności implementacyjne (alg. Dekkera zależny od liczby synchronizowanych procesów) Mechanizmy wysokopoziomowe użyteczne w programowaniu współbieżnym Mechanizmy synchronizacji semafory rejony krytyczne monitory Mechanizmy synchronizacji i komunikacji spotkania symetryczne i asymetryczne przestrzenie krotek potoki, komunikaty i kanały Pojęcie semafora Dijkstra (1965r.) Definicja abstrakcyjnego typu danych wraz z operacjami umożliwiającymi wstrzymywanie i wznawianie procesów: określenie stanu początkowego podniesienie semafora (signal(s), V(s)) opuszczenie semafora (wait(s), P(s)) Operacje niepodzielne – w danej chwili może być wykonywana tylko jedna z nich. Typy semaforów Propozycje Dijkstry: semafor ogólny semafor binarny Późniejsze rozszerzenia: semafor uogólniony semafor dwustronnie ograniczony Definicja semafora Zmienna całkowita z wyróżnionymi operacjami: • podniesienia semafora (signal(s)): s:=s+1 • opuszczenia semafora (wait(s)): czekaj na (s>0); s:=s-1 Definicja nie gwarantuje, że wszystkie procesy zostaną kiedyś wznowione. „Praktyczna” definicja operacji na semaforze Opuszczenie semafora (wait(s)) • jeżeli s>0, to s:=s-1 • jeśli s=0, to wstrzymaj proces wywołujący operację; Podniesienie semafora (signal(s)) • jeżeli istnieją procesy wstrzymane przez opuszczony semafor s, to wznów jeden z nich • jeśli nie, to s:=s+1; Założenia dodatkowe wait i signal to jedyne dozwolone operacje na semaforze w szczególności zabronione jest testowanie wartości s i jej zmiana (z wyj. ustawienia początkowego) operacje te są pierwotne – wykluczają się nawzajem; jeśli wywołane są równocześnie, zostaną wykonane jedna po drugiej (nie wiadomo w jakiej kolejności) algorytm wyboru procesów wznawianych nie powinien powodować zagłodzenia żadnego z oczekujących procesów (cecha uczciwości) „Praktyczna” definicja semafora binarnego Opuszczenie semafora (wait(s)) • jeżeli s=1, to s:=0 • jeśli s=0, to wstrzymaj proces wywołujący operację; Podniesienie semafora (signal(s)) • jeżeli istnieją procesy wstrzymane przez opuszczony semafor s, to wznów jeden z nich • jeśli nie, to s:=1; Wzajemne wykluczanie Program wykl_sem; var s (*binarny*): semaphore procedure p1; begin repeat wait(s); kryt1; signal(s); lok1; forever end; ... p2 analogicznie begin (program główny) s:=1; cobegin p1;p2; coend end. Analiza modelu igloo Podobne do rozwiązania ze zmienną-kluczem Testowanie i zerowanie semafora w funkcji pierwotnej wait(s) – brak problemów z blokowaniem się nawzajem. Problem producentakonsumenta(1) Konieczność zapewnienia producentowi miejsca na zapamiętanie danych do chwili ich skonsumowania przez konsumenta. repeat produkuj rekord v; b[in]:=v; in:=in+1; forever repeat wait until in>out; w:=b[out]; out:=out+1; konsumuj rekord w; forever Wariant z buforem nieograniczonym - semafor s jako licznik zliczający różnicę między ilością porcji włożonych do bufora, a pobranych z niego (s=in-out). Kod Program pr-kon-sem; var n: semaphore; procedure producent; begin repeat produkuj; włóż; * signal(n); forever end; procedure konsument; begin repeat wait(n); pobierz; * konsumuj; forever end; * włóż i pobierz – pewne abstrakcyjne operacje na buforze begin (* program główny *) n:=0; cobegin producent; konsument; coend end. Modelowanie procesów współbieżnych 12 Modyfikacja rozwiązania Założenie: instrukcje włóż i pobierz stanowią strefy krytyczne. Konieczność użycia dwóch semaforów: ogólnego n (zlicza ilość elementów bufora) binarnego s dla uzyskania wzajemnego wykluczania operacji na buforze. Kod Program pr-kon-sem; var n: semaphore; s: (*binary) semaphore; procedure producent; begin repeat produkuj; wait(s); włóż; signal(s); signal(n); forever end; procedure konsument; begin repeat wait(n); wait(s); pobierz; signal(s); konsumuj; forever end; begin (* program główny *) n:=0; s:=1; cobegin producent; konsument; coend end. Modelowanie procesów współbieżnych 14 Kod Ważna kolejność operacji wait i signal dla poszczególnych semaforów (wartości zmiennych można testować tylko w instrukcjach wait, co może powodować zawieszenie niektórych procesów) Przykładowo zmiana kolejności operacji wait w procedurze konsumenta może prowadzić do blokady systemu (gdy konsument wykona procedurę przy n=0) procedure konsument; begin repeat wait(s); wait(n); pobierz; signal(s); konsumuj; forever end; Modelowanie procesów współbieżnych 15 Problem producentakonsumenta(2) Wariant z buforem ograniczonym: bufory cykliczne – indeksy tablicy obliczane modulo jej długość bufory zwielokrotnione – dwa podobne bufory, z których jeden jest aktualnie zapewniany przez programistę, a drugi opróżniany przez konsumenta Rozwiązanie semaforowe: semafor ogólny n zlicza włożone do bufora elementy semafor ogólny e zlicza puste miejsca w buforze semafor binarny s zapewnia wzajemne wykluczanie Kod Program pr-kon-ogr; const rozmiarbufora=...; var n: semaphore; e: semaphore; s: (*binary) semaphore; procedure producent; begin repeat produkuj; wait(e); wait(s); włóż; (*kryt*) signal(s); signal(n); forever end; procedure konsument; begin repeat wait(n); wait(s); pobierz; (*kryt*) signal(s); signal(e); konsumuj; forever end; begin (* program główny *) n:=0;s:=1;e:=rozmiarbufora; cobegin producent; konsument; coend end. Modelowanie procesów współbieżnych 17 Rozszerzenia definicji(1) Semafor dwustronnie ograniczony - nie może przyjmować wartości ujemnych oraz nie może przekroczyć pewnej dodatniej wartości. Symetria operacji podnoszenia i opuszczania: jeżeli S=0 (S=N) to wstrzymaj działanie procesu wykonującego tę operację; jeśli nie, to jeśli są procesy wstrzymane w wyniku podnoszenia (opuszczania) semafora, to wznów jeden z nich, jeśli nie, to s:=s-1 (s:=s+1) Klasyczny semafor w dowolnej interpretacji też jest ograniczony od dołu Rozszerzenia definicji(2) Semafor uogólniony - wartość semafora może być zmieniana o dowolną wartość naturalną. Operacja opuszczania (wait(s,n)): jeżeli s>=n, to s:=s-n; w przeciwnym razie to wstrzymaj działanie procesu wykonującego tę operację; Operacja podnoszenia (signal(s,n)): jeśli są procesy wstrzymane w wyniku opuszczania semafora wait(s,m), to wznów jeden z nich i s:=sm+n; jeśli nie, to s:=s+n Zasadnicze cechy semaforów Eleganckie narzędzie synchronizacji Słaba czytelność programów Podatność na błędy – zmiana kolejności wykonywanych instrukcji może prowadzić do zawieszenia procesów, a także systemu operacyjnego. Regiony krytyczne Przemodelowanie operacji semaforowych w kierunku strukturalizacji. Konieczność stworzenia instrukcji obejmującej sekcję krytyczną. Dla sekcji należy zapewnić wzajemne wykluczanie. Służy ona do wykonania operacji na pewnym zasobie (zmiennej); niedopuszczalne jest operowanie na zmiennej poza sekcją krytyczną. Struktura regionu krytycznego Zmienna dzielona – obiekt typu T, na którym są wykonywane operacje wewnątrz sekcji krytycznej var v: shared T; Instrukcja regionu krytycznego – instrukcja strukturalna tworząca sekcję krytyczną dla instrukcji I1,...,IN wiążąca ją ze zmienną v region v do I1,...,IN end Założenia: wewnątrz związanych ze sobą regionów krytycznych może pracować tylko jeden proces skończony czas przebywania procesu w regionie wejście do regionu musi być udostępnione dowolnemu procesowi w skończonym czasie Przykład – synchronizacja dostępu do zasobów var R: shared resource; procedure pp; begin repeat lok1; region R do request R; hold(t); release R; end; lok2; forever end; procedure process(1..N) pp; end; begin (* program główny *) cobegin process(1); ... process(N); coend end. Warunkowe rejony krytyczne Uzupełnienie r.k. o prostą komunikację między procesami Wśród instrukcji wewnątrz regionu dowolną ilość razy może wystąpić instrukcja synchronizacji await Jeśli warunek Wi jest spełniony, proces przechodzi do wykonania następnej instrukcji; jeśli nie, zostaje zawieszony do czasu spełnienia warunku z jednoczesnym zwolnieniem dostępu do sekcji krytycznej var R: shared resource; ... region R do I1; I2;...;await W1 ... Ii; Ii+1;...;await Wj ... IN-1;IN end; uproszczenie implementacji mniejsze prawdopodobieństwo wystąpienia blokady i zagłodzenia Monitory Rozwinięcie (uogólnienie) mechanizmu regionów krytycznych Zebrane w jednej konstrukcji programowej wyróżnione zmienne oraz procedury i funkcje na nich operujące; część procedur jest udostępniana na zewnątrz monitora – jest to jedyny sposób dostępu do zmiennych monitora dla procesów Wykonanie procedury monitora jest sekcją krytyczną wykonującego go procesu Możliwość wstrzymywania i wznawiania procesów wewnątrz procedury monitorowej – zmienne typu condition, operacje wait(c) – wstrzymanie procesu wykonującego operację i wstawienie go na koniec kolejki związanej ze zmienną c (z jednoczesnym zwolnieniem monitora) signal(c) – wznowienie pierwszego procesu wstrzymanego w kolejce związanej z c; jeżeli nie jest to ostatnia operacja procedury monitorowej, proces wywołujący czeka na zwolnienie monitora przez proces wznowiony (struktura stosu) Przejście przez monitor Monitor M Process A M.P(y) 1 Procedure P(x:real); begin ... wait(c); ... signal(c); ... end; 1 – procesy oczekujące na wejście 2 – oczekujące na c 3 – wstrzymane przez signal(c) (stos) 2 3 Ograniczenia monitorów Jeśli każdy z wstrzymanych procesów czekałby na inną wartość zmiennej c, dla każdej z tych wartości powinno się zaimplementować oddzielną kolejkę. Rozwiązania: - dynamiczna struktura „pamiętająca” potrzeby każdego z procesów - dwie „podkolejki” – w pierwszej tylko jeden proces, wykorzystanie zmiennej pomocniczej przechowującej warunek żądany - przerzucenie sprawdzania wartości monitora na procesy czekające – ginie kolejność wstrzymywanych procesów Problem producenta i konsumenta Program prodkons; const rozmiarbufora=...; monitor bufor; b:array[0..rozmiarbufora] of integer; in,out,n:integer; procedure włóż(var v:integer) begin if n=rozmiarbufora+1 (*bufor pełny*) wait(n<rozmiarbufora) then „czekaj aż nie będzie pełny”; b[in]:=v; in:=in+1; if in=rozmiarbufora+1 then in:=0; n:=n+1; „zasygnalizuj, że bufor nie jest pusty” signal(n!=0) end; Kod monitora cd. procedure pobierz(var v:integer) begin if n=0 wait(n!=0) (*bufor pusty*) then „czekaj, aż nie będzie pusty”; v:=b[out]; out:=out+1; if out=rozmiarbufora+1 then out:=0; n:=n-1; signal(n<rozmiarbufora) begin end; „zasygnalizuj, że bufor nie jest pełny”; end; (*treść monitora*) in:=0; out:=0; n:=0; Kod producenta i konsumenta procedure producent; var v:integer; begin repeat produkuj(v); włóż(v); forever end; procedure konsument; var v:integer; begin repeat pobierz(v); konsumuj(v); forever end; begin (*program główny*) cobegin producent; konsument; coend end.