SYSTEMY OPERACYJNE

 


Wykład 6

Synchronizowanie procesów


 


Ogólna struktura typowego procesu Pi .

Struktura procesu Pi w algorytmie 1


Struktura procesu Pi w algorytmie 2

T0: P0 ustala znacznik[0] = true
T1: P1 ustala znacznik[1] = true

po których procesy P0 i P1 zapętlają się na zawsze w swoich instrukcjach while


#3 Algorytm 3

Struktura procesu Pi w algorytmie 3


        var wybrane: array [0..n-1] of boolean;
               numer: array [0..n-1] of integer;

       Na początku elementy tych struktur danych przyjmują odpowiednio wartości

repeat

wybrane[i]:=true;
numer[i]:=max(numer[0],numer[1], ..., numer[n-1]) + 1;
wybrane[i]:=false;
for j:=0 to n-1
     do begin
           while
wybrane[j] do nic;
           while numer[j]<>0
               and (numer[j],i) < (numer[i],i) do nic;
    end;

sekcja krytyczna

numer[i]:=0;

reszta

until false;

 

         function Testuj-i-Ustal(var cel:boolean):boolean;
                  begin
                     
Testuj-i-Ustal:=cel;
                       cel:=true;
                 end;

  • ważną cechą tego rozkazu jest jest jego niepodzielne wykonanie, którego nie można przerwać;
  • jeśli zatem dwa takie rozkazy są wykonywane jednocześnie (każdy na innym procesorze), to będą wykonywane sekwencyjnie w dowolnym porządku;

repeat

while Testuj-i-Ustal(zamek) do nic;

 sekcja krytyczna

 zamek:=false;

reszta

until false


               czekaj(S):          while S<= 0 do nic;
                                        S:=S-1;

               sygnalizuj(S): S:=S+1;

  1. do rozwiązania problemu sekcji krytycznej z udziałem n procesów

repeat

czekaj(mutex);

 sekcja krytyczna

 sygnalizuj(mutex);

reszta

until false

  1. do rozwiązywania różnych problemów synchronizacji, np. dwa procesy współbieżne P1 z instrukcją S1 i P2 z instrukcją S2 chcemy, aby S2 została wykonana dopiero gdy zakończy się wykonanie S1


var bufor: shared record
           pula: array[0..n-1] of jednostka;
           licznik, we, wy: integer;
           end;

region bufor when licznik < n
   do begin
         pula[we]:=nastp;
         we:=we+1 mod n;
         licznik:=licznik + 1;
      end;
region bufor when licznik > 0
    do begin
          nastk:=pula[wy];
          wy:=wy+1 mod n;
          licznik:=licznik-1;
       end;
var mutex, pierwsza-zwłoka, druga-zwłoka: semaphore;
    pierwszt-licznik, drugi-licznik: integer;

- początkowo mutex=1, pozostałe semafory mają wartość 0

Za wyłączność dostępu do sekcji krytycznej odpowiada zmienna mutex. Jeśli proces nie może wejść do sekcji krytycznej z powodu fałszywości warunku boolowskiego B, to najpierw czeka pod semaforem pierwsza-zwłoka. Proces czekający pod semaforem pierwsza-zwłoka jest w końcu przenoszony do semafora druga-zwłoka, co poprzedza udzielenie mu zezwolenia na ponowne obliczenie boolowskiego B. Za pomocą zmiennych pierwszy-licznik i drugi-licznik pamięta się odpowiednio ile procesów oczekuje pod semaforami pierwsza-zwłoka i druga-zwłoka.

Jeśli jakiś proces opuszcza sekcję krytyczną, to może zmienić wartość jakiegoś warunku boolowskiego B, wzbraniającego innemu procesowi wejścia do sekcji krytycznej. Biorąc to pod uwagę, należy przejrzeć kolejkę procesów czekających pod semaforami pierwsza-zwłoka i dryga-zwłoka (w tej kolejności) i pozwolić, by każdy proces przetestował wyrażenie boolowskie. Proces testujący to wyrażenie może odkryć, że jego obecna wartość jest równa true. Wówczas proces wchodzi do sekcji krytycznej. W przeciwnym razie proces musi nadal czekać pod semaforami pierwsza-zwłoka i druga-zwłoka, jak opisaliśmy poprzednio.

region x when B do S;

można zrealizować:

czekaj(mutex);
while not B
  do begin
     pierwszy-licznik:=pierwszy-licznik + 1;
     if drugi-licznik > 0
       then sygnalizuj(druga-zwłoka)
       else sygnalizuj(mutex);
     czekaj (pierwsza-zwłoka);
     pierwszy-licznik:=pierwszy-licznik - 1;
     drugi-licznik:=drugi-licznik + 1;
     if pierwszy-licznik > 0
       then sygnalizuj(pierwsza-zwłoka)
       else sygnalizuj(drugi-licznik);
     czekaj(druga-zwłoka);
     drugi-licznik:=drugi-licznik - 1;
  end;
S;
if pierwszy-licznik > 0
  then sygnalizuj(pierwsza-zwłoka)
  else if drygi-licznik > 0
         then sygnalizuj(druga-zwłoka)
         else sygnalizuj(mutex);
- implementacja konstrukcji regiony warunkowego

 


 


 Plan 1, czyli plan szeregowy, w którym transakcja T0 poprzedza transakcję T1 

T0  T1
czytaj(A)  
pisz(A)  
  czytaj(A)
  pisz(A)
czytaj(B)  
pisz(B)  
  czytaj(B)
  pisz(B)

 

Plan 2: szeregowalne zaplanowanie współbieżne

T0 

T1
czytaj(A)  
pisz(A)  
  czytaj(A)
  pisz(A)
czytaj(B)  
pisz(B)  
  czytaj(B)
  pisz(B)

. . . . . - operacje konfliktowe

. . . . . - operacje niekonfliktowe

T2 T3
czytaj(B)  
  czytaj(B)
  pisz(B)
czytaj(A)  
  czytaj(A)
  pisz(A)

Plan 3: zaplanowanie możliwe przy użyciu protokołu ze znacznikami czasu


<<< THE END >>>