Obliczenia w wyłącznych grupach

W systemie działa N grup procesów. Każdy proces cyklicznie wykonuje procedure własne sprawy, a następnie procedurę OBLICZ, którą w tym samym czasie mogą wykonywać tylko procesy należące do tej samej grupy. Pierwszy proces z grupy może rozpocząć wykonywanie procedury OBLICZ tylko wówczas, gdy nikt inny jej nie wykonuje. Po zakończeniu wykonywania procedury OBLICZ procesy czekają aż wszystkie wykonujące ją procesy zakończą jej wykonywanie. Po zakończeniu procedury przez ostatni z wykonujących ją procesów działanie powinny rozpocząć oczekujące procesy z kolejnej grupy. Zwróć uwagę, że mowa tu jest o wszystkich wykonywanych procesach danej grupy, a nie o wszystkich procesach danej grupy. Oznacza to, że nie wszystkie procesy z danej grupy muszą wykonać OBLICZ, aby rozpoczęła działanie następna grupa. Uzupełnij treść procesu P używając semaforów.

procedure rozpoczecie_obliczen(gr: 1..N)
begin
...
end;
procedure zakonczenie_obliczen(gr: 1..N)
begin
...
end;

process Proces(gr: 1..N)
begin
while (true) do
 begin
  WLASNE_SPRAWY();
  rozpoczecie_obliczen();
  OBLICZ();
  zakonczenie_obliczen();
 end;
end; 

Rozwiązanie:

var
  ochrona: binary semaphore := 1;
  pierwsi: binary semaphore := 0;
  oczekiwanie_na_zakonczenie: binary semaphore := 0;
  grupa_aktywna: integer := 0;
  reszta_grupy_czeka: array [1..N] of binary semaphore := {N times 0};
  liczba_czekajacych: array [1..N] of integer := {N times 0};
  liczba_aktywnych: integer := 0;
  liczba_aktywnych_zakonczonych: integer := 0;
  ile_grup_czeka: integer := 0;


procedure rozpoczecie_obliczen(gr: 1..N)
begin
 P(ochrona);
 if (grupa_aktywna=0) then
  begin
   grupa_aktywna:=gr;
  end;
 if (ile_grup_czeka>0 || grupa_aktywna<>gr) then
  begin
   liczba_czekajacych[gr]++;
   if (liczba_czekajacych[gr]>1) then
    V(ochrona);
    P(reszta_grupy_czeka[gr]);
   else
    begin
     ile_grup_czeka++;
     V(ochrona);
     P(pierwsi);
     ile_grup_czeka--;
     grupa_aktywna := gr;
    end; 
   liczba_czekajacych[gr]--;
   liczba_aktywnych++;
   if (liczba_czekajacych[gr]>0) then
    V(reszta_grupy_czeka[gr]);
   else
    V(ochrona);
  end;
 else
  begin
   liczba_aktywnych++;
   V(ochrona);
  end; 
end;

procedure zakonczenie_obliczen(gr: 1..N)
begin
 P(ochrona);
 liczba_aktywnych_zakonczonych++;
 if (liczba_aktywnych<>liczba_aktywnych_zakonczonych) then
  begin
   V(ochrona);
   P(oczekiwanie_na_zakonczenie);
  end;
 liczba_aktywnych--;
 if (liczba_aktywnych<>0)
   V(oczekiwanie_na_zakonczenie);
 else
  begin
   grupa_aktywna=0;
   liczba_aktywnych_zakonczonych=0;
   if (ile_grup_czeka>0)
    V(pierwsi);
   else
    V(ochrona);
  end;
end;

process Proces(gr: 1..N)
begin
while (true) do
 begin
  WLASNE_SPRAWY();
  rozpoczecie_obliczen();
  OBLICZ();
  zakonczenie_obliczen();
 end;
end;