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.