1 Zadanie 1: Bar Programowanie wspóªbie»ne wiczenia 6 monitory cz. 2 Napisz monitor Bar synchronizuj cy prac barmana obsªuguj cego klientów przy kolistym barze z N stoªkami. Ka»dy klient realizuje nast puj cy algorytm: process Klient() { i = Bar.CzekamNaStoªekIPiwo(); // pij piwo na stoªku i tym Bar.ZwalniamStoªek(i); Barman nalewa piwo nowo przybyªym klientom w kolejno±ci wyznaczonej przez stoªki przez nich zajmowane (chodzi w kóªko): process Barman() { int i=0; i = Bar.KtoNast pny(i); // podej±cie do stoªka i tego i nalanie piwa Bar.Gotowe(i); Rozwi zanie monitor Bar { enum StanStoªka {wolny, nieobsªu»ony, obsªu»ony; / stan stoªka : nieobsªu»ony siedz cy na nim klient czeka na piwo obsªu»ony siedz cy na nim klient pije piwo / condition naklienta; / barman czeka, je»eli nie ma nic do roboty / condition nawej±cie; / klienci czekaj na wej±cie do baru / condition napiwo[n]; / klient czeka na nalanie piwa / int iluwbarze = 0; / ilu klientów jest w barze / iluczeka: int; / ilu klientów czeka na nalanie piwa / StanStoªka stoªek[n] = (wolny,..., wolny); int CzekamNaStoªekIPiwo(){ if (iluwbarze == N) (nawej±cie); / nie ma wolnych stoªków / iluwbarze++; iluczeka++; i = 0; while (stoªek[i ] <> wolny) i = (i + 1) % N; / klient szuka wolnego stoªka / stoªek [ i ] = nieobsªu»ony; / i ty stoªek byª wolny, klient go zajmuje /
2 (naklienta); / zwalnia barmana, je»eli ten czeka / (napiwo[i]); / czeka na stoªku i tym na piwo / return i; void ZwalniamStoªek(int i){ iluwbarze ; stoªek [ i ] = wolny; (nawej±cie); int KtoNast pny(int ostatnio){ if (iluczeka == 0) (naklienta); / nie ma nieobsªu»onych klientów / i = (ostatnio + 1) % N; / barman szuka klienta pocz wszy od nast pnego miejsca po tym, które ostatnio obsªugiwaª / while (stoªek[i ] <> nieobsªu»ony) i = (i + 1) % N; return i; void Gotowe(int i){ stoªek [ i ] = obsªu»ony; iluczeka ; (napiwo[i]); Uwagi Stan stoªka musi by okre±lony przez trzy warto±ci. Je±li trzymamy informacj tylko o tym, czy stoªek jest wolny, czy zaj ty, a rozró»niamy stoªki obsªu»one od nieobsªu»onych sprawdzaj c czy kolejki z nimi zwi zane s niepuste, to mamy rozwi zanie niepoprawne. Klient w CzekamNaSto- ªekIPiwo() wykonuje (napiwo[i]) po (naklienta). Zgodnie z semantyk operacji po wykonaniu (naklienta) zaczyna dziaªa barman, który sprawdzaj c kolejk napiwo[i] stwierdza,»e jest ona pusta, poniewa» klient nie wykonaª jeszcze (napiwo[i]). Ten sam problem wyst puje, je»eli przyjmiemy zaªo»enie,»e nalanie piwa jest wewn trzn czynno±ci w monitorze, czyli procedury KtoNast pny() i Gotowe() zª czymy w jedn. Barman szukaj c nie obsªu»onego klienta nie mo»e zaczyna zawsze od tego samego miejsca, poniewa» prowadzi to do zagªodzenia. Dlaczego nie skorzystali±my z wygodniejszych struktur danych takich jak lista zamiast tablicy? Poniewa» barman szukaj c klienta nie mógªby wzi pierwszego z listy oczekuj cych powinien obsªugiwa wszystkich czekaj cych klientów, obok których przechodzi, niezale»nie od tego w jakiej kolejno±ci przyszli. Ten problem mo»na rozwi za porz dkuj c list wedªug numerów stoªków, przy których siedz klienci, jednak wtedy pojawia si nowa trudno± od którego miejsca nale»y rozpocz,»eby nie spowodowa zagªodzenia? Jak wida rozwi zanie korzystaj ce z tablicy jest prostsze. Zadanie 2: Šadowanie cegieª Grupa N (N > 0) robotników ma zaªadowa stert cegieª na samochód. Ka»dy z nich musi wiedzie od kogo ma odbiera cegªy i komu podawa, czyli musi zna numery obu swoich s siadów (nale»y przyj,»e sterta cegieª ma numer 0, a samochód N+1). Prac mo»na rozpocz dopiero wtedy, gdy zgªosz si wszyscy robotnicy. Po zako«czeniu zaªadunku robotnicy przychodz po wypªat. Ka»dy podaje swoj stawk za prac, na podstawie której wylicza si stawk ±redni, któr otrzymuj wszyscy. Ka»dy robotnik dziaªa wedªug schematu:
3 process Robotnik (int id) { int mojastawka =...; int lewy, prawy, wypªata; Zaªadunek.Chc Pracowa (id, &lewy, &prawy); podawajcegªy(lewy, prawy); Zaªadunek.Wypªata(mojaStawka, &wypªata); odpoczynek(wypªata); Nale»y napisa monitor Zaªadunek. Dodatkowe wymaganie: nie wolno deklarowa»adnych struktur rozmiaru N lub wi kszego. Rozwi zanie Aby pozna numer prawego s siada nie u»ywaj c dodatkowych struktur danych nale»y odwróci kolejno± procesów wykorzystuj c do tego operacj. Przypominamy,»e wstrzymuje dziaªanie procesu do momentu, gdy zwalniany przez niego proces opu±ci monitor. Procesy wstrzymane przy wykonaniu operacji zwalniane s w kolejno±ci odwrotnej do tej w jakiej j wykonywaªy. monitor Zaªadunek { int ilu =0, ostatni=0, stawka=0; condition napozostaªych; void chc Pracowa (int id, &lewy, &prawy) { lewy = ostatni; if ( ilu < N) { (napozostaªych); prawy = ostatni; else { prawy = N + 1; ilu = 0; void Wypªata(int mojastawka, &wypªata) { if ( ilu == 1) ostatni = 0; stawka = stawka + mojastawka; if ( ilu < N) (napozostaªych) else stawka = stawka / N; wypªata = stawka;
4 Przeanalizujmy wykonanie procesów na przykªadzie 4 robotników, którzy zgªaszaj si w kolejno±ci: 2, 3, 4, 1. 2 4 3 1 lewy=0 lewy=2 lewy=4 lewy=3 prawy=n+1 (pusty) prawy=1 prawy=3 prawy=4 Nie potrzeba osobnych kolejek do wstrzymywania procesów czekaj cych na prac i na wypªat, poniewa» nie ma niebezpiecze«stwa,»e procesy z tych dwóch grup si przemieszaj. Rozwi zanie niepoprawne Zwró my uwag,»e nast puj ce rozwi zanie nie jest poprawne: void chc Pracowa (int id, &lewy, &prawy) { lewy = ostatni; if ( ilu < N) (napozostaªych) else ostatni = N+1; prawy = ostatni; ilu ; if not empty(napozostaªych) Ka»dy z procesów musi pozna swoich s siadów: lewego, czyli proces, który zgªosiª si bezpo±rednio przed nim i prawego, czyli proces, który zgªosiª si bezpo±rednio po nim - ten wªa±nie warunek nie jest speªniony. Przeanalizujmy to na naszym przykªadzie.
2 4 3 1 lewy=0 lewy=2 lewy=4 lewy=3 ostatni=n+1 prawy=n+1 prawy=1 (bª d) prawy=2 (bª d) prawy=4 (bª d) (pusty) 5