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:
monitor Dyskoteka; dj_gra: condition; dj_spi: condition; parkiet: condition; czeka_partner: array [0..1] of condition; ilu_na_parkiecie: integer := 0; id: integer; export procedure CzekajNaPartneraIMiejsce(nr: integer, plec: integer, partner: integer) begin if (empty(czeka_partner[1-plec])) then begin wait(czeka_partner[plec]); partner := id; id := nr; end; else begin id := nr; signal(czeka_partner[1-plec]); partner := id; end; if (K - ilu_na_parkiecie <= 1) then begin wait(parkiet); end; ilu_na_parkiecie++; signal(dj_spi); end; export procedure Koncz() begin ilu_na_parkiecie--; if (K - ilu_na_parkiecie > 1) then begin signal(parkiet); signal(parkiet); end; if (ilu_na_parkiecie = 0) then begin signal(dj_gra); end; end; export procedure CzekajNaNiepusty() begin if (ilu_na_parkiecie = 0) wait(dj_spi); end; export procedure CzekajNaPusty() begin if (ilu_na_parkiecie <> 0) wait(dj_gra); end;
Rozważmy pewną sytuację. System zaczyna działać, DJ zaczyna się wykonywać i stwierdza, że nie ma nikogo na parkiecie, w efekcie zasypia na zmiennej warunkowej dj_spi. Następnie przychodzą dwa procesy różnej płci, tworzą parę, wchodzą na parkiet i budzą proces DJ. DJ opuszcza procedurę CzekajNaNiepusty i jest na zewnątrz monitora. Procesy w tym czasie opuszczają parkiet, wysyłają przy tym sygnał na zmienną warunkową dj_gra, na której DJ nie czeka, gdyż jest ciągle na zewnątrz monitora. Następnie DJ wywołuje CzekajNaPusty i w tym momencie musi sprawdzić czy rzeczywiście ma czekać na zmiennej dj_gra, gdyż nie powinien tego robić bez sprawdzenia warunku (nie ma żadnego procesu na parkiecie).
Analogiczna sytuacja ma miejsce, gdy DJ znajduje się na zewnątrz i wykonuje np. wylaczmuzyke. W momencie gdy DJ jest w tej procedurze, do systemu mogą przyjść dwa procesy, uformować parę i wejść na parkiet. Z tego powodu DJ wykonując CzekaNaNiepusty przed zatrzymaniem się na zmiennej warunkowej dj_spi musi sprawdzić czy rzeczywiście parkiet jest pusty.
W procedurach CzekajNaNiepusty i CzekajNaPusty występuje instrukcja warunkowa. Jest to spowodowane tym, że proces DJ opuszcze monitor między wywołaniami tych procedur. Gdy DJ jest poza monitorem stan systemu (parkietu) może ulec zmianie. Proces DJ po wejściu do monitora musi sprawdzić stan systemu (wykonując właśnie instrukcję warunkową). Można rozważyć przypadek gdy DJ wykonuje się cały czas w monitorze - wtedy DJ nie musi sprawdzać stanu systemu, gdyż wie, że proces, który go obudził wykonywał się bezpośrednio przed nim i proces DJ ma gwarancję, że od tamtego czasu stan monitora nie uległ zmianie.
monitor Dyskoteka; dj_gra: condition; dj_spi: condition; parkiet: condition; czeka_partner: array [0..1] of condition; ilu_na_parkiecie: integer := 0; id: integer; export procedure CzekajNaPartneraIMiejsce(nr: integer, plec: integer, partner: integer) begin if (empty(czeka_partner[1-plec])) then begin wait(czeka_partner[plec]); partner := id; id := nr; end; else begin id := nr; signal(czeka_partner[1-plec]); partner := id; end; if (K - ilu_na_parkiecie <= 1) then begin wait(parkiet); end; ilu_na_parkiecie++; signal(dj_spi); end; export procedure Koncz() begin ilu_na_parkiecie--; if (K - ilu_na_parkiecie > 1) then begin signal(parkiet); signal(parkiet); end; if (ilu_na_parkiecie = 0) then begin signal(dj_gra); end; end; export procedure DJ_service() begin while (true) do; begin wait(dj_spi); wlaczmuzyke; wait(dj_gra); wylaczmuzyke; end; end;