1 Programowanie wspóªbie»ne wiczenia 5 monitory cz. 1 Zadanie 1: Stolik dwuosobowy raz jeszcze W systemie dziaªa N par procesów. Procesy z pary s nierozró»nialne. Ka»dy proces cyklicznie wykonuje wªasnesprawy, a potem spotyka si z drugim procesem z pary w kawiarni przy stoliku dwuosobowym (funkcja randka()). W kawiarni jest tylko jeden stolik. Procesy zajmuj stolik tylko wtedy, gdy obydwa s gotowe do spotkania, natomiast mog odchodzi od niego pojedynczo, czyli w ró»nym czasie ko«czy wykonywanie funkcji randka(). Rozwi zanie Schemat rozwi zania jest taki sam jak poprzednio. Zamiast semaforów u»yjemy nast puj cych zmiennych warunkowych (kolejek): zmiennej, na której czekaj procesy, które przyszªy jako pierwsze z pary, zmiennej, na którym drugie procesy z pary czekaj na stolik. Potrzebna b dzie równie» informacja o liczbie procesów siedz cych przy stoliku. void randka(); process P(int j) { / j to numer pary / while (true) { wªasnesprawy; Kawiarnia.Chc _stolik(j); randka(); Kawiarnia.Zwalniam_stolik(); monitor Kawiarnia{ condition napar [N]; condition nastóª; int przystole = 0; void Chc _stolik(int j) { if (empty(napar [j])) wait(napar [j]); / pierwszy z pary / / drugi z pary / if ( przystole > 0) wait(nastóª); przystole = 2; signal(napar [j ]); void Zwalniam_stolik() { przystole ; if ( przystole == 0) signal(nastóª);
2 Zwró my uwag na nast puj ce ró»nice mi dzy zaproponowanym rozwi zaniem a rozwi zaniem korzystaj cym z semaforów z wicze«3: Nie trzeba synchronizowa dost pu procesów do zmiennych monitora (brak jawnego odpowiednika semafora ochrona). Nie musimy tego robi, poniewa» procedur monitora nie mo»e wykonywa wiele procesów jednocze±nie. Nie potrzebujemy równie» dodatkowej tablicy przechowuj cej dla ka»dej pary informacj o tym, czy pierwszy proces z pary ju» czeka. Wystarczy sprawdzi niepusto± kolejki, na której ma czeka ten proces. Operacja wait() jest zawsze blokuj ca w przeciwie«stwie do semaforowej operacji P(), która zale»y od warto±ci semafora. Dlatego w rozwi zaniu korzystaj cym z semaforów mamy: P(nastóª), a w obecnym rozwi zaniu: if (przystole > 0) wait(nastóª). Operacja signal() na pustej kolejce nie robi nic w przeciwie«stwie do operacji V(), która wykonana na semaforze, na którym»aden proces nie czeka, powoduje jego podniesienie (otwarcie). Zadanie 2: Symulacja monitora za pomoc semaforów Korzystaj c z semaforów nale»y napisa odpowiedniki operacji monitorowych: 1. rozpocz cia wykonywania procedury monitora, 2. operacji wait(), 3. operacji signal(), 4. zako«czenia wykonywania procedury monitora. Rozwi zanie - wersja 1 W pierwszej wersji rozwi zania zakªadamy,»e signal() jest ostatni instrukcj w procedurze monitora. semaphore Monitor = 1; / zapewnia wzajemne wykluczanie przy wykonywaniu procedur monitora / semaphore Kolejka = 0; / ka»d zmienn warunkow monitora / int ileczeka = 0; / symulujemy za pomoc semafora i licznika oczekuj cych / 1. P(Monitor); 2. ileczeka ++; V(Monitor); P(Kolejka); / dziedziczenie sekcji krytycznej / ileczeka ; 3. if ( ileczeka > 0) V(Kolejka) 4. V(Monitor); Dziedziczenie sekcji krytycznej jest konieczne, aby zachowa semantyk operacji monitorowych, czyli zagwarantowa,»e po wykonaniu signal() wykonuje si zwolniony proces. Dokªadn symulacj zapewni wyª cznie semafory silne.
3 Rozwi zanie - wersja 2 Tym razem nie zakªadamy,»e signal() jest ostatni instrukcj w procedurze monitora. semaphore Monitor = 1; / zapewnia wzajemne wykluczanie przy wykonywaniu procedur monitora / semaphore Stos = 0; / wstrzymuje procesy wstrzymane po signal / int ileczekas = 0; semaphore Kolejka = 0; / ka»d zmienn warunkow monitora / int ileczekak = 0; / symulujemy za pomoc semafora i licznika oczekuj cych / 1. P(Monitor); 2. ileczekak ++; if ( ileczekas > 0) V(Stos) P(Kolejka); ileczekak ; 3. if ( ileczekak > 0) { ileczekas ++; V(Kolejka); P(Stos); ileczekas ; 4. if ( ileczekas > 0) V(Stos) Procesy wykonuj ce wait() i ko«cz ce procedur monitora budz i przekazuj sekcj krytyczn procesom, które wykonaªy signal() oczekuj cym na semaforze Stos. Nie jest to oczywi±cie dokªadna implementacja, poniewa» za pomoc semaforów nie mo»na symulowa stosu. Procesy oczekuj ce po wykonaniu signal() wykonaj si przed procesami rozpoczynaj cymi procedur monitora, ale nie w wymaganej kolejno±ci. Zadanie 3: Zasoby W systemie s dwie grupy procesów korzystaj ce z N zasobów typu A i M zasobów typu B (N + M > 1). Procesy z pierwszej grupy cyklicznie wykonuj wªasne sprawy, po czym wywoªuj procedur zamie«ab(), która konsumuje jeden zasób A i produkuje jeden zasób B. Procesy z grupy drugiej cyklicznie wykonuj wªasne sprawy, po czym wywoªuj procedur zamie«(), która konsumuje jeden zasób dowolnego typu i produkuje zasób przeciwny. Zsynchronizuj procesy za pomoc monitora tak, aby: procedury zamie«ab() i zamie«() byªy wywoªywane przez procesy jedynie pod warunkiem dost pno±ci odpowiednich zasobów, procesy z grupy pierwszej wykonywaªy procedur zamie«ab() parami, tzn. proces z grupy pierwszej mo»e rozpocz wykonanie procedury jedynie wtedy, gdy jest inny proces z grupy pierwszej gotowy do jej wykonania (i oczywi±cie niezb dne zasoby), jednocze±nie mogªo odbywa si wiele operacji na zasobach, ale nie doszªo do zagªodzenia»adnej grupy procesów. Monitor powinien udost pnia jedynie procedury wywoªywane przez procesy przed i po rozpocz ciu korzystania z zasobów.
4 Rozwi zanie Przyjmijmy,»e procesy z grupy pierwszej przed zamian wykonuj procedur ChceA() monitora, a procesy grupy drugiej ChceZasób(), która przekazuje w wyniku typ przyznanego zasobu. Po wykonaniu zamiany wszystkie procesy wykonuj Wyprodukowaªem(Zasób z) podaj c typ zasobu, który zostaª wyprodukowany. monitor Zasoby{ int ilea = N; int ileb = M int ilunaa = 0; condition zasóba, zasób, partner; void ChceA() { ilunaa++; if (ilunaa % 2 == 1) wait(partner) / pierwszy z pary czeka na partnera / / drugi z pary / if (ilea < 2) / je»eli nie ma dwóch zasobów A / wait(zasóba); / czeka na co najmniej dwa zasoby A / ilea = ilea 2; signal(partner); / zwalnia partnera / ilunaa ; Zasób ChceZasób() { if ((ileb == 0) && (ilea == 0 ilunaa >= 2)) wait (zasób); / czeka na dowolny zasób / if (ileb > 0) { / najpierw B,»eby produkowa A / ileb ; return(b); return(a); void Wyprodukowaªem(Zasób z) { if (z == B) { ileb++; signal(zasób); ilea++; if (empty(zasóba)) / tylko je»eli nie ma par w pierwszej grupie / signal(zasób); / to zwalniamy drug grup / else / czeka para na zasób A / if (ilea > 1) / zwalniamy j, je±li mo»na / signal(zasóba); / wpp czekamy na drugi egzemplarz zasobu A /
Aby nie zagªodzi procesów pierwszej grupy, proces który wyprodukowaª A, zwalnia procesy drugiej grupy tylko wtedy, gdy nie ma pary gotowych procesów z grupy pierwszej, nawet je»eli jest tylko jeden zasób, który na razie jest dla tej pary bezu»yteczny. Alternatywne rozwi zanie monitor Zasoby{ int ilea = N; int ileb = M condition zasóba, zasób, partner; void ChceA() { if (ilea == 0) wait(zasóba); / zapewniam sobie zasób / if (empty(partner)) wait(partner); / pierwszy z pary czeka na partnera / else signal(partner); / drugi zwalnia partnera / Zasób ChceZasób() { if (ileb + ilea == 0) wait (zasób); / czeka na dowolny zasób / if (ileb > 0) { / najpierw B,»eby produkowa A / ileb ; return(b); return(a); void Wyprodukowaªem(Zasób z) { if (z == B) { ileb++; signal(zasób); ilea++; if (empty(zasóba)) / tylko je»eli nie ma oczekuj cych z pierwszej grupy / signal(zasób); / zwalniamy drug grup / else signal(zasóba); W drugim rozwi zaniu proces z pierwszej grupy rezerwuje dla siebie zasób, a dopiero potem czeka na partnera. 5