Wady mechanizmów niskopoziomowych Ingerencja w kod systemu operacyjnego (przerwania) Programowanie na niskim 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; repeat wait(s); kryt1; signal(s); lok1; forever... p2 analogicznie (program główny) s:=1; co 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; repeat produkuj; włóż; * signal(n); forever procedure konsument; repeat wait(n); pobierz; * konsumuj; forever * włóż i pobierz pewne abstrakcyjne operacje na buforze (* program główny *) n:=0; co 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. 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)
Kod Program pr-kon-sem; var n: semaphore; s: (*binary) semaphore; procedure producent; repeat produkuj; wait(s); włóż; signal(s); signal(n); forever procedure konsument; repeat wait(n); wait(s); pobierz; signal(s); konsumuj; forever (* program główny *) n:=0; co producent; konsument; coend end. Modelowanie procesów współbieżnych 14
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; repeat produkuj; wait(e); wait(s); włóż; (*kryt*) signal(s); signal(n); forever procedure konsument; repeat wait(n); wait(s); pobierz; signal(s); signal(e); konsumuj; forever (*kryt*) (* program główny *) n:=0; co producent; konsument; coend end. Modelowanie procesów współbieżnych 16
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 góry
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 (wait(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 I 1,...,I N wiążąca ją ze zmienną v region v do I 1,...,I N 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; repeat lok1; region R do request R; hold(t); release R; lok2; forever procedure process(1..n) pp; (* program główny *) co 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 W i 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 I 1 ; I 2 ;...;await W 1... I i ; Ii+1 ;...;await W j... I N-1 ;I N 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 Process A Monitor M M.P(y) 1 Procedure P(x:real);... wait(c);... signal(c);... 3 2 1 procesy oczekujące na wejście 2 oczekujące na c 3 wstrzymane przez signal(c) (stos)
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) if n=rozmiarbufora+1(*bufor pełny*) 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
Kod monitora cd. procedure pobierz(var v:integer) if 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; zasygnalizuj, że bufor nie jest pełny ; (*treść monitora*) in:=0; out:=0; n:=0;
Kod producenta i konsumenta procedure producent; var v:integer; repeat produkuj(v); włóż(v); forever procedure konsument; var v:integer; repeat pobierz(v); konsumuj(v); forever (*program główny*) co producent; konsument; coend end.