W pewnej dyskotece bawią się procesy. Jednocześnie na parkiecie może przebyać co najwyżej K>1 procesów. Każdy proces przychodząc na dyskotekę czeka na dowolny proces odmiennej płci, po czym oba procesy czekaja na wolne miejsca na parkiecie, po czym razem idą tańczyć. Każdy z nich kończy taniec niezależnie od drugiego. W dyskotece pracuje też DJ, który dba o to, aby muzyka grała wtedy i tylko wtedy, gdy parkiet jest niepusty (tak, to oznacza, że muzyka może nigdy nie zamilknąć).
process Proces(nr: integer; plec: 0..1)
var
partner: integer;
begin
while (true) do
begin
DYSKOTEKA.CzekajNaPartneraIMiejsce(nr, plec, partner);
tancz();
DYSKOTEKA.Koncz();
end;
end;
process DJ
begin
while (true) do
begin
DYSKOTEKA.CzekajNaNiepusty;
wlaczmuzyke;
DYSKOTEKA.CzekajNaPusty;
wylaczmuzyke;
end;
end;
Napisz monitor DYSKOTEKA. Obowiązuje semantyka monitora z ćwiczeń.
Rozwiązanie:
Najpierw można się zastanowić nad rozwiązaniem prostszego problemu: procesy przychodzą same na dyskotekę i same tańczą.
monitor DYSKOTEKA;
czeka_dj: condition;
gra_dj: condition;
czeka_proces: condition;
muzyka_gra: boolean := false;
liczba_aktywnych: integer := 0;
procedure Czekaj_na_dj_i_miejsce()
begin
if (not muzyka_gra or liczba_aktywnych=K) then
begin
if (not czeka_dj.empty()) then
signal(czeka_dj);
wait(czeka_proces);
end;
liczba_aktywnych++;
if (liczba_aktywnych<K) then
signal(czeka_proces);
end;
procedure Koncz()
begin
liczba_aktywnych--;
if (not empty(czeka_proces))
signal(czeka_proces);
else if (liczba_aktywnych=0) then
signal(gra_dj);
end;
procedure CzekajNaNiepusty
begin
if (empty(czeka_proces)) then
wait(czeka_dj);
end;
procedure CzekajNaPusty
begin
muzyka_gra := true;
signal(czeka_proces); {:parkiet musi byc pusty, gdyz nie grala muzyka, wiec mozna kogos wpuscic:}
wait(gra_dj);
muzyka_gra := false;
end;
Teraz zajmijmy się ustawieniem procesów w pary. Zapomnijmy na razie o procesie DJ i muzyce a zajmijmy się ustawieniem procesów w pary, i tym, żeby na parkiecie nie było jednocześnie więcej niż K procesów. W monitorze procesy czekające na zmiennych condition czekają w kolejkach prostych, to rozwiązanie korzysta z tego faktu.
liczba_m: integer := 0;
liczba_k: integer := 0;
czeka_pierwszy: condition;
czeka_drugi: condition;
id_1: integer;
id_2: integer;
liczba_aktywnych: integer := 0;
procedure Czekaj_na_miejsce()
begin
if (K-liczba_aktywnych<2) then
wait(czeka_drugi);
end;
procedure Czekaj(nr: integer, plec: integer, partner: integer)
var
pierwszy: bool;
begin
if (plac=M) then
begin
liczba_m++;
if (liczba_m>liczba_k) then
pierwszy := true;
else
pierwszy := false;
end;
else
begin
liczba_k++;
if (liczba_m<liczba_k) then
pierwszy := true;
else
pierwszy := false;
end;
if (pierwszy) then
wait(czeka_pierwszy);
partner := id_1;
id_2 := nr;
liczba_aktywnych++;
else
Czekaj_na_miejsce();
id_1 := nr;
signal(czeka_pierwszy);
partner := id_2;
liczba_aktywnych++;
end;
procedure Koncz()
begin
liczba_aktywnych--;
if (K-liczba_aktywnych>1) then
signal(czeka_drugi);
end;
Łącząc rozwiązania podproblemów, można rozwiązać problem przedstawiony w zadaniu.
liczba_m: integer := 0;
liczba_k: integer := 0;
czeka_pierwszy: condition;
czeka_proces: condition;
id_1: integer;
id_2: integer;
liczba_aktywnych: integer := 0;
procedure Czekaj_na_dj_i_miejsce()
begin
if (not muzyka_gra or K-liczba_aktywnych<2) then
begin
if (not czeka_dj.empty()) then
signal(czeka_dj);
wait(czeka_proces);
end;
end;
procedure Czekaj(nr: integer, plec: integer, partner: integer)
var
pierwszy: bool;
begin
if (plac=M) then
begin
liczba_m++;
if (liczba_m>liczba_k) then
pierwszy := true;
else
pierwszy := false;
end;
else
begin
liczba_k++;
if (liczba_m<liczba_k) then
pierwszy := true;
else
pierwszy := false;
end;
if (pierwszy) then
wait(czeka_pierwszy);
partner := id_1;
id_2 := nr;
liczba_aktywnych++;
else
Czekaj_na_dj_i_miejsce();
id_1 := nr;
signal(czeka_pierwszy);
partner := id_2;
liczba_aktywnych++;
if (K-liczba_aktywnych>1) then
signal(czeka_proces);
end;
procedure Koncz()
begin
liczba_aktywnych--;
if (not empty(czeka_proces) and K-liczba_aktywnych>1) then
signal(czeka_proces);
else if (liczba_aktywnych=0) then
signal(gra_dj);
end;