1 / 39

Systemy operacyjne

Systemy operacyjne. Wykład 7 Synchronizacja procesów i wątków. dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki http://wbieniec.kis.p.lodz.pl/pwsz. Sytuacje hazardowe.

vinny
Download Presentation

Systemy operacyjne

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Systemy operacyjne Wykład 7 Synchronizacja procesów i wątków dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki http://wbieniec.kis.p.lodz.pl/pwsz

  2. Sytuacje hazardowe W systemach wielozadaniowych, podczas realizacji przez ustalona liczbę procesów dostępu współbieżnego do dzielonych zasobów może dojść do sytuacji hazardowych, nazywanych również wyścigiem (ang. race condition). Zjawiska te pojawiają się, kiedy następuje przeplot operacji modyfikacji lub operacji modyfikacji i odczytu stanu współdzielonego zasobu, przy czym operacje te pochodzą od różnych procesów. Jeśli dostęp do zasobu ogranicza się wyłącznie do odczytu, to jest dostępem zawsze bezpiecznym, nawet jeśli dochodzi od przeplotu operacji. Sytuacje hazardowe występują zarówno w przypadku procesów, jak i wątków Obojętnym jest również, czy system komputerowy, w którym są wykonywane procesy jest wyposażony w jeden, czywiększąliczbęprocesorów.

  3. Przykład wyścigu Rozważmy dwa procesy, które chcą zmodyfikować wartość współdzielonej zmiennej, przy czym pierwszy chce te wartość zwiększyć o jeden, a drugi zmniejszyć o jeden. Przyjmijmy, ze wartość początkowa zmiennej wynosi 5. Zakładamy, ze pojedynczy proces, aby zmodyfikować wartość zmiennej musi ją najpierw pobrać z pamięci operacyjnej, zapisać w rejestrze , wykonać właściwą operacje, a następnie zapisać wynikową wartość do pamięci. Procesy wykonujące wspomniane operacje mogą utracić procesor w każdej chwili, np.: w wyniku zadziałania mechanizmu wywłaszczającego.

  4. Wyścig – scenariusz 1 czas Proces P1 Proces P2 1 Odczytaj wartość z pamięci (M=5) i umieść ja w rejestrze R1. (R1=5) NOP 2 Zwiększ wartość rejestru R1 o jeden. (R1=6) NOP 3 NOP Odczytaj wartość z pamięci (M=5) i umieść ją w rejestrze R1. (R1=5) 4 NOP Zmniejsz zawartość rejestru R1 o jeden. (R1=4) 5 Zapisz zawartość rejestru R1 do pamięci. (M=6) NOP 6 NOP Zapisz zawartość rejestru R1 do pamięci. (M=4) WynikWartość wynosi 4 (jako ostatni swój wynik do pamięci zapisał proces drugi). Tymczasem prawidłowym wynikiem jest 5.

  5. Wyścig – scenariusz 2 czas Proces P1 Proces P2 1 Odczytaj wartość z pamięci (M=5) i umieść ja w rejestrze R1. (R1=5) NOP 2 NOP Odczytaj wartość z pamięci (M=5) i umieść ją w rejestrze R1. (R1=5) 3 Zwiększ wartość rejestru R1 o jeden. (R1=6) NOP 4 NOP Zmniejsz zawartość rejestru R1 o jeden. (R1=4) 5 NOP Zapisz zawartość rejestru R1 do pamięci. (M=4) 6 Zapisz zawartość rejestru R1 do pamięci. (M=6) NOP WynikWartość wynosi 6 (jako ostatni swój wynik do pamięci zapisał proces pierwszy). Tymczasem prawidłowym wynikiem jest 5.

  6. Sekcja krytyczna Fragment kodu, podczas którego realizacji proces wykonuje dostęp do zasobów współdzielonych nazywamy sekcją krytyczną. Zasoby te mogą być fizyczne lub logiczne. Zasoby mogą mieć prostą budowę (jak zmienne prostych typów) lub złożoną (jak struktury danych). Aby dostęp do zasobu współdzielonego był bezpieczny musimy zagwarantować niepodzielność wykonania przez procesy sekcji krytycznych. Jeśli jeden z procesów korzystających z zasobu dzielonego rozpoczął wykonywanie sekcji krytycznej, to żaden z pozostałych procesów nie może rozpocząć wykonywania sekcji krytycznej dotyczącej tego samego zasobu, dopóki ten pierwszy jej nie skończy. Rozpoczynanie sekcji krytycznej określamy mianem wchodzenia do sekcji krytycznej. Kończenie sekcji nazywamy wychodzeniem lub opuszczaniem sekcji krytycznej. Część kodu bezpośrednio poprzedzającą sekcję krytyczną nazywamy sekcją wejściową. Część umieszczoną bezpośrednio za sekcją krytyczną nazywamy sekcją wyjściową. Pozostała część kodu procesu to reszta.

  7. Poprawność obsługi sekcji krytycznej Każde rozwiązanie problemu sekcji krytycznej musi spełniać trzy warunki, aby być w pełni poprawnym: Wzajemne wykluczanie (ang. mutual exclusion) W danym czasie, w sekcji krytycznej może znajdować się tylko jeden proces. Postęp Jeśli nie wymaga tego warunek wzajemnego wykluczania, to proces nie powinien być wstrzymywany przed wejściem do sekcji krytycznej. Ograniczone czekanie Oczekiwanie każdego procesu na wejście do sekcji krytycznej powinno kiedyś się zakończyć. Inne procesy nie mogą wstrzymywać go w nieskończoność przed wejściem do sekcji krytycznej.

  8. Poprawne rozwiązanie dla dwóch procesów(algorytm Petersona) Współdzielone zmienne wymagane przez algorytm int flaga[2]; //tablica flag gotowości procesów do wejścia do s.k int numer;//numer procesu, któremu zezwolono wejsc do s.k. ProcesP0 ProcesP1 while(1) { flaga[0] = 1; numer = 1; while(flaga[1]==1 && numer ==1) {;} Sekcja_Krytyczna0(); flaga[0] = 0; Reszta0(); } while(1) { flaga[1] = 1; numer = 0; while(flaga[0]==1 && numer ==0) {;} Sekcja_Krytyczna1(); flaga[1] = 0; Reszta1(); }

  9. Dowód poprawności rozwiązania Wzajemne wykluczanie Jeden z dwóch procesów wchodzi do sekcji krytycznej wtedy i tylko wtedy, kiedy jego flaga ma wartość true lub gdy zmienna numer zawiera jego identyfikator. Może zaistnieć sytuacja, w której oba procesy będą miały ustawione flagi, ale zmienna numer może przyjąć tylko jedną wartość, a więc jeden z nich będzie wykonywał pętlę while, a drugi wejdzie do sekcji krytycznej. Postęp Załóżmy, ze proces o numerze 0 chce wejść do sekcji krytycznej, a proces o numerze 1 nie jest nią zainteresowany (bo wykonuje swoja resztę). Zmienna numer będzie miała wartość 1, ale flaga procesu o numerze 1 nie będzie ustawiona, a więc proces 0 nie zostanie powstrzymany przed wejściem do sekcji krytycznej. Ograniczone oczekiwanie Instrukcja przypisania z sekcji wyjściowej gwarantuje, że proces będzie czekał na wejście do sekcji krytycznej tylko do momentu, gdy drugi z procesów zakończy swoją sekcję krytyczną i wykona sekcję wyjściową.

  10. Poprawne rozwiązanie programowe dla wielu procesów Uogólnienie przedstawionego rozwiązania na n procesów jest możliwe ale otrzymany kod jest mniej czytelny niż w przypadku dwóch procesów. Zmianie ulegają typy zmiennych współdzielonych. Zmienna numer ma większy zakres, również flagi mogą teraz przyjmować trzy wartości: puste – proces jest poza sekcja krytyczna, gotowy – proces zgłasza swa gotowość do wejścia do sekcji krytycznej, w sekcji – proces jest w sekcji krytycznej. Zmienna j jest zmienna niewspółdzielona (poza właścicielem tej zmiennej, żaden inny proces nie ma do niej dostępu).

  11. Kod rozwiązania dla i–tego procesu Współdzielone zmienne wymagane przez algorytm enum stan{puste, gotowe, w_sekcji}; stan flaga[n]; int numer[n]; ProcesPi int j; while(1){ do { flaga[i]=gotowy; j =numer; while (i!=j) { if (flaga[j]!=puste) j=numer; else j=(j+1)% n; } flaga[i]=w sekcji ; j= 0; while (j<n && (j==i || flaga[j]!=w sekcji)) j++; }while(j<n || (numer!=i && flaga[numer]!=puste)); numer=i; Sekcja_Krytyczna(); j=(numer+1) % n; while (flaga[j]==puste) j=(j+1)%n; numer=j; flaga[i]=puste; Reszta(); }

  12. Dowód poprawności Wzajemne wykluczanie Proces z grupy procesów ubiegających się o dostęp do współdzielonego zasobu wchodzi do sekcji krytycznej wtedy i tylko wtedy, gdy jego flaga gotowości ma wartość w_sekcji, a flagi pozostałych procesów mają inną wartość. Ponieważ tylko on może ustawić swoją flagę na wspomnianą wartość oraz dokonuje sprawdzenia flag pozostałych procesów po jej ustawieniu, to warunek wzajemnego wykluczania jest zachowany. Postęp Wartość zmiennej numer ulega zmianie tylko wtedy gdy proces wchodzi lub wychodzi z sekcji krytycznej. Jeśli tylko jeden proces jest zainteresowany wejściem do sekcji krytycznej, a żaden inny nie wykonuje jej, ani nie ubiega sie o wejście do niej, to może on wykonać sekcję krytyczną poza kolejnością wyznaczaną przez zmienną numer. Ograniczone oczekiwanie Każdy proces opuszczający sekcję krytyczną w sekcji wejściowej wyznacza swojego następcę do wejścia do sekcji krytycznej. W ten sposób każdy proces, który ubiega się o wykonanie sekcji krytycznej dostanie pozwolenie po co najwyżej n-1 próbach.

  13. Algorytm piekarni Nazwa pochodzi od sposobu w jaki piekarnie sprzedają chleb. Każdy proces ubiegający się o wejście do sekcji krytycznej musi się zarejestrować i otrzymać swój numer. Im niższa jest wartość tego numeru, tym szybciej jest jego właściciel obsługiwany. Może zdarzyć się, że dwa procesy o trzymają ten sam numer. Taki konflikt rozstrzyga się porównując ich identyfikatory(PID), które też są numerami.

  14. Algorytm piekarni Współdzielone zmienne wymagane przez algorytm int wybrane[n]; int numer[n]; Proces Pi while(1){ wybrane[i] = 1; numer[i]=max(numer,n)+1; wybrane[i]=0; for(j=0;j<n;j++) { while(wybrane[j]){;} while(numer[j]!=0 && cmp2(numer[j],j,numer[i],i)<0) {;} } SekcjaKrytyczna(i); numer[i]=0; Reszta(i); } Uwaga: należy zdefiniować funkcje max i cmp2

  15. Dowód poprawności Wzajemne wykluczanie Każdy proces, który wchodzi do sekcji krytycznej otrzymuje numer, który jest następnikiem największego z dotychczas wybranych numerów. Ponieważ operacja wybierania nie jest niepodzielna, to dodatkowo sprawdzane są unikatowe numery identyfikacyjne procesów, gdyby pojawiły sie dwa lub większa liczba o takich wybranych numerach. Operacja porównania numerów wstrzymywana jest do czasu zakończenia wybierania numeru przez nadchodzące procesy. To wszystko gwarantuje spełnienie warunku wzajemnego wykluczania. Postęp Ponieważ tylko procesy gotowe do wejścia do sekcji krytycznej wybierają numery, to zapewniony jest warunek postępu. Ograniczone oczekiwanie Procesy wchodzą do sekcji krytycznej w takim porządku w jakim nadeszły, a więc spełnienie warunku ograniczonego czekania jest zapewnione.

  16. Środki synchronizacji Algorytm Petersena i algorytm piekarni są rozwiązaniami programowymi. Teoretycznie są poprawne. Niestety, w praktyce te rozwiązania mogą zawieść, jeśli program będzie wykonywany na procesorze stosującym wykonywanie instrukcji poza kolejnością (ang. out of order execution). Poprawność tych rozwiązań może również być naruszona podczas wykonywania przez kompilator optymalizacji kodu wynikowego. Stosując te rozwiązania należy pamiętać o dodatkowych środkach, które pozwalają uniknąć opisanych problemów. Inną wadą przedstawionych algorytmów są problemy z zastosowaniem ich do bardziej skomplikowanych zadań. Najprostszym sposobem zapewnienia wyłączności i niepodzielności wykonania sekcji krytycznej jest wyłączenie na czas jej działania systemu przerwań. Niestety to rozwiązanie może prowadzić do większych problemów (możliwość powstania wyjątku w sekcji krytycznej). Nie daje sie ono również zastosować w systemach wieloprocesorowych (tu każdy procesor ma własny system przerwań).

  17. Niepodzielne rozkazy sprzętowe Większość współczesnych architektur sprzętowych oferuje rozkazy, które pozwalają wykonać w sposób niepodzielny, na prostych zmiennych takie operacje, jak dodawanie, odejmowanie, operacje binarne. Istnieją również rozkazy pomagające rozwiązać problem sekcji krytycznej dla operacji na strukturach danych. Rozkaz Testuj i ustaw W sposób niepodzielny odczytuje wartość zmiennej, a następnie ją modyfikuje. Rozkaz Wymień Dokonuje zamiany wartości dwóch zmiennych, które pełnia role zamka i klucza. Oba rozkazy pozwalają zapewnić spełnienie warunku wzajemnego wykluczania. W systemach wieloprocesorowych, w których procesory dysponują wspólną pamięcią operacyjną istnieją rozkazy pozwalające zablokować pozostałym procesorom dostęp do określonej części pamięci na czas wykonywania przez jeden z nich sekcji krytycznej.

  18. Semafor Semafor jest zmienną całkowitą, do której dostęp można uzyskać (poza inicjalizacją) jedynie za pomocą dwóch specjalnych operacji: czekaj P (hol. Proben, ang. wait) sprawdza, czy semafor ma wartość większą od zera. Jeśli nie to czeka aż osiągnie taką wartość, a następnie zmniejsza ją o jeden. Operacja zmniejszania jest wykonywana w sposób niepodzielny. sygnalizuj V (hol. Verhogen, ang. signal). Operacja sygnalizuj w całości jest wykonywana niepodzielnie i polega na zwiększeniu wartości semafora o jeden. Istnieją różne wersje semaforów, niektóre z nich mogą przyjmować różne wartości, inne tylko dwie (tzw. semafory binarne, muteksy). Istnieją również różne sposoby implementacji operacji czekaj. O procesie, który oczekuje na podniesienie semafora w kolejce mówimy, że został uśpiony, a proces, który został wybrany z tej kolejki do opuszczenia semafora mówimy, ze został obudzony.

  19. Implementacja semafora Semafor to: Bieżąca wartość + Lista (np. FIFO) procesów oczekujących class Semaphore { int value; ProcessList pl; public: Semaphore(int a) {value=a;} void Wait (); void Signal (); }; Semaphore::Wait() () { value -= 1; if (value < 0) { Add(this_process,pl); Sleep (this_process); } } Semaphore::Signal () { value += 1; if (value <= 0) { Process P=Remove(P); Wakeup (P); } } Nieco zmodyfikowana implementacja – zakładamy że wartość zmiennej może być ujemna – wtedy przechowuje ona liczbę wstrzymanych procesów Zakładamy dostępność dwóch funkcji na poziomie jądra systemu: Sleep: realizuje przejście procesu Aktywny=>Oczekujący Wakeup: Oczekujący=>Gotowy Wait i Signal muszą być operacjami atomowymi – ich wykonanie nie może być przerwane przełączeniem kontekstu do innego procesu.

  20. Regiony krytyczne semafory są skuteczne w rozwiązywaniu sekcji krytycznej i proste w zastosowaniu, jednak mogą być dosyć niewygodne w użyciu, tym samym prowadząc do powstania błędów logicznych w programach. Programista może np. zapomnieć o umieszczeniu w programie instrukcji podnoszącej semafor. W takim wypadku może dojść do zablokowania działania wszystkich procesów czekających na podniesienie semafora. W językach programowania wprowadzono instrukcje pozwalające tworzyć tzw. regiony krytyczne

  21. Regiony krytyczne sharedintalpha; pozwala na określenie zmiennej, jako współdzielonej przez kilka procesów region alphado {/* ciąg operacji */}; gwarantuje, ze operacja wykonana na zmiennej współdzielonej będzie niepodzielna. Konstrukcja regionu warunkowego: regionalphawhen warunek {/* ciąg operacji */}; Operacja zostanie wykonana, tylko wtedy, kiedy warunek będzie spełniony. Warunek sprawdzany jest nie przed wejściem do sekcji krytycznej, ale w trakcie jej trwania. Do realizacji oczekiwania na spełnienie warunku służy instrukcja await(warunek); volatileintzmienna; Informacja dla kompilatora, aby nie korzystać z rejestrów do operacji na tej zmiennej. Wszelkie operacje dokonywane na tej zmiennej, są dokonywane bezpośrednio w pamięci operacyjnej komputera, w tej jej części, która została przydzielona dla tej zmiennej.

  22. Rozwiązanie problemu sekcjikrytycznej przy pomocy semaforów SemaphoreSem(1); voidProcess() { while (1) { Sem.Wait(); // Proces wykonuje swoją sekcję krytyczną Sem.Signal() // Proces wykonuje pozostałe czynności } }

  23. Klasyczne problemy synchronizacji Każde nowe rozwiązanie problemu synchronizacji musi zostać poddane testom potwierdzającym jego poprawność. Istnieje kilka dobrze poznanych problemów, które tworzą zestaw testowy dla takich rozwiązań. Problem ograniczonego buforowania Problem czytelników i pisarzy Problem pięciu ucztujących filozofów Problem śpiącego fryzjera

  24. Problem producenta-konsumenta z ograniczonym buforem Jeden proces (producent) generuje (produkuje) dane a drugi (konsument) je pobiera (konsumuje). Wiele zastosowań w praktyce np. drukowanie. Jedno z rozwiązań opiera się na wykorzystaniu tablicy działającej jak bufor cykliczny, co pozwala na zamortyzowanie chwilowych różnic w szybkości producenta i konsumenta. Tę wersję problemu nazywa się problemem z ograniczonym buforem. Problem: jak zsynchronizować pracę producenta i konsumenta – np. producent zapełnia bufor, konsument usiłuje pobrać element z pustego bufora.

  25. Producent konsument z buforem cyklicznym Zmienne wspólne constint n; // rozmiar bufora typedef … Item; Itembuffer[n]; // bufor int out=0; // indeks konsumenta intin = 0; // indeks producenta counter = 0; // liczba elementów w buforze Producent umieszcza element w buforze na pozycji inlub czeka, jeżeli counter==n, tzn. bufor pełny Konsument pobiera element z bufora z pozycji out lub czeka, jeżeli counter==0 tzn. bufor pusty. Zmienne in oraz out zmieniane są zgodnie z regułą i=(i+1)%n

  26. Algorytm dla jednej pary procesów Producent Konsument Item element; while(1) { element = Produkuj(); while (counter == n) ; buffer[in] = element; in = (in+1) % n; counter ++; } Itemelem; while(1) { while (counter == 0) ; elem = buffer[out]; out = (out+1) % n; counter --; Konsumuj(elem); } dlaczego rozwiązanie jest niepoprawne dla więcej niż jednego konsumenta albo producenta ? Counter jest zmienną współdzieloną przez obydwa procesy. Co się może stać gdy jednocześnie obydwa procesy spróbują ją zmienić?

  27. Problem producenta-konsumenta Architektura RISC: ładuj do rejestru, zwiększ wartość, zapisz wynik. Niech x oznacza jest modyfikowaną zmienną counter. Przyjmijmy, że x=5 Rozważmy dwie możliwe kolejności wykonywania instrukcji poszczególnych procesów. – a) Poprawna wartość 5. – b) Niepoprawna wartość 4. Wybór jednej z tych wielkości niedeterministyczny. Sytuacja wyścigu

  28. producent-konsument z wykorzystaniem semaforów Zmienne wspólne constint n; Semaphoreempty(n); /*zlicza liczby pustych miejsc w tablicy. Wstrzymuje producenta gdy w tablicy nie ma wolnego miejsca*/ Smaphorefull(0); /*zlicza liczbę elementów w buforze (pełnych miejsc w tablicy). Wstrzymuje konsumenta gdy w buforze nie ma żadnego elementu.*/ Semaphoremutex(1); /* zapewnia wzajemne wykluczanie przy dostępie do zmiennych współdzielonych*/ Itembuffer[n]; Producent Konsument Item element; intin =0; while(1) { element = Produkuj(); empty.Wait(); mutex.Wait(); buffer[in] = element; in = (in+1) % n; mutex.Signal(); full.Signal(); } Itemelem; int out = 0; while(1) { full.Wait(); mutex.Wait(); elem = buffer[out]; out = (out+1) % n; mutex.Signal(); empty.Signal(); Konsumuj(elem); }

  29. Blokada, Zakleszczenie, (ang. deadlock) Zbiór procesów jest w stanie blokady, kiedy każdy z nich czeka na zdarzenie, które może zostać spowodowane wyłącznie przez jakiś inny proces z tego zbioru. Samochody nie mają wstecznego biegu = Brak wywłaszczeń zasobów

  30. Przykład blokady Sekwencja instrukcji prowadząca do blokady. Semaphore A(1),B(1); P0 wykonał operacje A.Wait() Proces P0 A.Wait(); B.Wait(); . . . B.Signal(); A.Signal(); Proces P1 B.Wait(); A.Wait(); . . . A.Signal(); B.Signal(); P1 wykonał operacje B.Wait() P0 usiłuje wykonać B.Wait() P1 usiłuje wykonać A.Wait() P0 czeka na zwolnienie B przez P1 Będą czekały w nieskończoność !!! Do blokady może (ale nie musi) dojść.

  31. Przykład blokady #define MAX 512 main(intargc, char* argv[]) { intpd[2]; pipe(pd); if(fork()==0) {//procespotomny dup2(pd[1], 1); execvp("ls", argv); } else {// proces macierzysty char buf[MAX]; intlb, i; close(pd[1]); wait(0); while((lb=read(pd[0],buf,MAX))>0) { for(i=0; i<lb; i++) buf[i] = toupper(buf[i]); write(1, buf,lb); } } } Proces macierzysty czeka z przetwarzaniem znaków aż proces potomny zakończy się. Jeżeli potok zapełni się (cały listing nie zmieści się naraz) to proces ls nie może się zakończyć. Proces macierzysty nie może rozpocząć opróżniania potoku, bo czeka na zakończenie ls. Spowoduje to powstanie zakleszczenia.

  32. Przykład blokady w łączu nazwanym #include <fcntl.h> #define MAX 512 main(intargc, char* argv[]) { intfd; mkfifo("/tmp/fifo", 0600); if (fork() == 0){ // proces potomny close(1); open("/tmp/fifo", O_WRONLY); execvp("ls", argv); } else { // proces macierzysty char buf[MAX]; intlb, i; wait(0); pd = open("/tmp/fifo",O_RDONLY); while((lb=read(fd,buf,MAX))>0) { for(i=0; i<lb; i++) buf[i] = toupper(buf[i]); write(1, buf, lb); } } } Proces potomny próbuje otworzyć kolejkę FIFO do zapisu W tym miejscu zawiesi się, aż inny proces otworzy kolejkę do odczytu. Proces macierzysty nie może otworzyć kolejki, bo linijkę wyżej czeka na zakończenie procesu potomnego. Nastąpi zakleszczenie. W tym wypadku z pomocą mógłby przyjść inny proces, który na chwilę otworzy kolejkę do odczytu.

  33. Opis formalny: graf alokacji zasobów Okrąg oznacza proces, a prostokąt zasób. Strzałka od procesu do zasobu => proces czeka na zwolnienie zasobu Strzałka od zasobu do procesu => proces wszedł w posiadanie zasobu. Stan blokady ma miejsce, wtedy i tylko wtedy gdy w grafie alokacji zasobów występuje cykl. Jedna z metod uniknięcia blokady => nie dopuszczaj do powstania cyklu. Np. każdy proces wchodzi w posiadanie zasobów w określonym porządku (identycznym dla wszystkich procesów).

  34. Zagłodzenie procesów (starvation) Proces czeka w nieskończoność, pomimo że zdarzenie na które czeka występuje. (Na zdarzenie reagują inne procesy) Przykład: Jednokierunkowe przejście dla pieszych, przez które w danej chwili może przechodzić co najwyżej jedna osoba. Osoby czekające na przejściu tworzą kolejkę Z kolejki wybierana jest zawsze najwyższa osoba Bardzo niska osoba może czekać w nieskończoność Zamiast kolejki priorytetowej należy użyć kolejki FIFO (wybieramy tę osobę, która zgłosiła się najwcześniej) Przykład: z grupy procesów gotowych planista krótkoterminowy przydziela zawsze procesor najpierw procesom profesorów a w dalszej kolejności procesom studentów. Jeżeli w systemie jest wiele procesów profesorów, to w kolejce procesów gotowych znajdzie się zawsze co najmniej jeden i proces studenta będzie czekał w nieskończoność na przydział procesora.

  35. Problem pięciu filozofów Każdy filozof siedzi przed jednym talerzem Każdy filozof na przemian myśli i je Do jedzenia potrzebuje dwóch widelców Widelec po lewej stronie talerza Widelec po prawej stronie talerza W danej chwili widelec może być posiadany tylko przez jednego filozofa.

  36. Problem pięciu filozofów Może się zdarzyć, że wszyscy filozofowie zechcą jeść i jednocześnie sięgną po leżący po lewej stronie sztuciec. Okaże się, ze żaden z nich nie będzie mógł podnieść sztućca leżącego po prawej stronie (jest ich tylko pięć), koniecznego do spożycia posiłku. Jest to problem zakleszczenia Innym razem może dojść do zagłodzeniajednego z filozofów przez pozostałych biesiadników strategie rozwiązania tego problemu to Pozwolić jednocześnie zasiadać do stołu co najwyżej czterem filozofom Pozwolić podnosić filozofom sztućce tylko wtedy, gdy oba są dostępne Zastosować rozwiązanie asymetryczne: filozofowie o nieparzystych numerach podnoszą sztućce w kolejności lewy - prawy, a ci o numerach parzystych, w kolejności odwrotnej.

  37. Problem czytelników i pisarzy Wprowadzamy dwie klasy procesów: czytelników i pisarzy. Współdzielony obiekt nazywany jest czytelnią W danej chwili w czytelni może przebywać Jeden proces pisarza i żaden czytelnik, lub Dowolna liczba czytelników i żaden pisarz. Rozwiązanie Potraktować czytelnię jak obiekt wymagający wzajemnego wykluczania wszystkich typów procesów. Rozwiązanie prymitywne, ponieważ ma bardzo słabą wydajność. Jeżeli na wejście do czytelni czeka wielu czytelników i żaden pisarz to możemy wpuścić od razu wszystkich czytelników. Istnieją rozwiązania: – Z możliwością zagłodzenia pisarzy – Z możliwością zagłodzenia czytelników – Poprawne

  38. Problem śpiącego fryzjera Jeden proces fryzjera i wiele procesów klientów Współdzielone zasoby: n krzeseł w poczekalni i jedno krzesło fryzjera • Algorytm fryzjera: • Sprawdź czy jest ktoś w poczekalni • Jeżeli tak, to weź pierwszego z kolejki i strzyż, a następnie idź do kroku 1. • Jeżeli nie, usiądź w fotelu i śpij. Obudzi cię dzwonek do drzwi, wtedy przejdź do kroku 1. • Algorytm klienta: • Wejdź do salonu uruchamiając dzwonek. • Sprawdź, czy jest wolne miejsce w poczekalni. Jeżeli tak, to usiądź na końcu kolejki. Jeżeli nie – wyjdź z salonu.

  39. Literatura Beej's Guide to Unix IPC http://beej.us/guide/bgipc/ Ważniak – laboratorium z systemów operacyjnych http://wazniak.mimuw.edu.pl/index.php?title=Systemy_operacyjne#Laboratorium Robert Love: Linux. Programowanie systemowe. Helion 2008 Stevens R.W.: Programowanie w środowisku systemu UNIX. WNT, 2002 Havilland K., Gray D., Salama B.: Unix - programowanie systemowe. ReadMe, 1999 Arkadiusz Chrobot: Wykład: Systemy Operacyjne. Katedra Informatyki Politechniki Świętokrzyskiej Wojciech Kwedlo: Wykład: Systemy operacyjne Wydział Informatyki, Politechnika Białostocka

More Related