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;