Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Systemy operacyjne Wykład 7 Synchronizacja procesów i wątków dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki

Podobne prezentacje


Prezentacja na temat: "Systemy operacyjne Wykład 7 Synchronizacja procesów i wątków dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki"— Zapis prezentacji:

1 Systemy operacyjne Wykład 7 Synchronizacja procesów i wątków dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki 1

2 Sytuacje hazardowe 2 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, czy większą liczbę procesorów.

3 Przykład wyścigu 3 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 4 Proces P1Proces P2czas Odczytaj wartość z pamięci (M=5) i umieść ja w rejestrze R1. (R1=5) NOP Zwiększ wartość rejestru R1 o jeden. (R1=6) NOP Odczytaj wartość z pamięci (M=5) i umieść ją w rejestrze R1. (R1=5) Zmniejsz zawartość rejestru R1 o jeden. (R1=4) NOP Zapisz zawartość rejestru R1 do pamięci. (M=6) Zapisz zawartość rejestru R1 do pamięci. (M=4) NOP Wynik Wartość wynosi 4 (jako ostatni swój wynik do pamięci zapisał proces drugi). Tymczasem prawidłowym wynikiem jest 5.

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

6 Sekcja krytyczna 6 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 7 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) 8 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. 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. Współdzielone zmienne wymagane przez algorytm while(1) { flaga[0] = 1; numer = 1; while(flaga[1]==1 && numer ==1) {;} Sekcja_Krytyczna0(); flaga[0] = 0; Reszta0(); } 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(); } while(1) { flaga[1] = 1; numer = 0; while(flaga[0]==1 && numer ==0) {;} Sekcja_Krytyczna1(); flaga[1] = 0; Reszta1(); } Proces P0Proces P1

9 Dowód poprawności rozwiązania 9 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 10 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 11 enum stan{puste, gotowe, w_sekcji}; stan flaga[n]; int numer[n]; enum stan{puste, gotowe, w_sekcji}; stan flaga[n]; int numer[n]; Proces P i 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

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

14 Algorytm piekarni 14 int wybrane[n]; int numer[n]; int wybrane[n]; int numer[n]; while(1){ wybrane[i] = 1; numer[i]=max(numer,n)+1; wybrane[i]=0; for(j=0;j

15 Dowód poprawności 15 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 16 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 17 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. 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. Istnieją również rozkazy pomagające rozwiązać problem sekcji krytycznej dla operacji na strukturach danych.

18 Semafor 18 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 19 Semafor to: Bieżąca wartość + Lista (np. FIFO) procesów oczekujących 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. 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); }

20 Regiony krytyczne 20 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. W językach programowania wprowadzono instrukcje pozwalające tworzyć tzw. regiony krytyczne 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.

21 Regiony krytyczne 21 shared int alpha; pozwala na określenie zmiennej, jako współdzielonej przez kilka procesów region alpha do {/* ciąg operacji */}; gwarantuje, ze operacja wykonana na zmiennej współdzielonej będzie niepodzielna. Konstrukcja regionu warunkowego: region alpha when 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); volatile int zmienna; 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 sekcji krytycznej przy pomocy semaforów 22 Semaphore Sem(1); void Process() { while (1) { Sem.Wait(); // Proces wykonuje swoją sekcję krytyczną Sem.Signal() // Proces wykonuje pozostałe czynności } Semaphore Sem(1); void Process() { while (1) { Sem.Wait(); // Proces wykonuje swoją sekcję krytyczną Sem.Signal() // Proces wykonuje pozostałe czynności }

23 Klasyczne problemy synchronizacji 23 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 24 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 25 const int n; // rozmiar bufora typedef … Item; Item buffer[n]; // bufor int out=0; // indeks konsumenta int in = 0; // indeks producenta counter = 0; // liczba elementów w buforze const int n; // rozmiar bufora typedef … Item; Item buffer[n]; // bufor int out=0; // indeks konsumenta int in = 0; // indeks producenta counter = 0; // liczba elementów w buforze Zmienne wspólne Producent umieszcza element w buforze na pozycji in lub 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 26 Item element; while(1) { element = Produkuj(); while (counter == n) ; buffer[in] = element; in = (in+1) % n; counter ++; } Item element; while(1) { element = Produkuj(); while (counter == n) ; buffer[in] = element; in = (in+1) % n; counter ++; } Producent Item elem; while(1) { while (counter == 0) ; elem = buffer[out]; out = (out+1) % n; counter --; Konsumuj(elem); } Item elem; while(1) { while (counter == 0) ; elem = buffer[out]; out = (out+1) % n; counter --; Konsumuj(elem); } Konsument 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 27 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 28 Item element; int in =0; while(1) { element = Produkuj(); empty.Wait(); mutex.Wait(); buffer[in] = element; in = (in+1) % n; mutex.Signal(); full.Signal(); } Item element; int in =0; while(1) { element = Produkuj(); empty.Wait(); mutex.Wait(); buffer[in] = element; in = (in+1) % n; mutex.Signal(); full.Signal(); } Producent Item elem; int out = 0; while(1) { full.Wait(); mutex.Wait(); elem = buffer[out]; out = (out+1) % n; mutex.Signal(); empty.Signal(); Konsumuj(elem); } Item elem; int out = 0; while(1) { full.Wait(); mutex.Wait(); elem = buffer[out]; out = (out+1) % n; mutex.Signal(); empty.Signal(); Konsumuj(elem); } Konsument const int n; Semaphore empty(n); /*zlicza liczby pustych miejsc w tablicy. Wstrzymuje producenta gdy w tablicy nie ma wolnego miejsca*/ Smaphore full(0); /*zlicza liczbę elementów w buforze (pełnych miejsc w tablicy). Wstrzymuje konsumenta gdy w buforze nie ma żadnego elementu.*/ Semaphore mutex(1); /* zapewnia wzajemne wykluczanie przy dostępie do zmiennych współdzielonych*/ Item buffer[n]; const int n; Semaphore empty(n); /*zlicza liczby pustych miejsc w tablicy. Wstrzymuje producenta gdy w tablicy nie ma wolnego miejsca*/ Smaphore full(0); /*zlicza liczbę elementów w buforze (pełnych miejsc w tablicy). Wstrzymuje konsumenta gdy w buforze nie ma żadnego elementu.*/ Semaphore mutex(1); /* zapewnia wzajemne wykluczanie przy dostępie do zmiennych współdzielonych*/ Item buffer[n]; Zmienne wspólne

29 Blokada, Zakleszczenie, (ang. deadlock) 29 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 30 Sekwencja instrukcji prowadząca do blokady. P0 wykonał operacje A.Wait() 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ść. Semaphore A(1),B(1); Proces P0 A.Wait(); B.Wait();. B.Signal(); A.Signal(); Proces P1 B.Wait(); A.Wait();. A.Signal(); B.Signal();

31 Przykład blokady 31 #define MAX 512 main(int argc, char* argv[]) { int pd[2]; pipe(pd); if(fork()==0) {// proces potomny dup2(pd[1], 1); execvp("ls", argv); } else {// proces macierzysty char buf[MAX]; int lb, i; close(pd[1]); wait(0); while((lb=read(pd[0],buf,MAX))>0) { for(i=0; i

32 Przykład blokady w łączu nazwanym 32 #include #define MAX 512 main(int argc, char* argv[]) { int fd; 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]; int lb, i; wait(0); pd = open("/tmp/fifo",O_RDONLY); while((lb=read(fd,buf,MAX))>0) { for(i=0; i

33 Opis formalny: graf alokacji zasobów 33 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) 34 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 35 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 36 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łodzenia jednego 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 37 Wprowadzamy dwie klasy procesów: czytelników i pisarzy. W danej chwili w czytelni może przebywać Współdzielony obiekt nazywany jest czytelnią 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 38 Jeden proces fryzjera i wiele procesów klientów Współdzielone zasoby: n krzeseł w poczekalni i jedno krzesło fryzjera Algorytm fryzjera: 1.Sprawdź czy jest ktoś w poczekalni 2.Jeżeli tak, to weź pierwszego z kolejki i strzyż, a następnie idź do kroku 1. 3.Jeżeli nie, usiądź w fotelu i śpij. Obudzi cię dzwonek do drzwi, wtedy przejdź do kroku 1. Algorytm klienta: 1.Wejdź do salonu uruchamiając dzwonek. 2.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 39 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 Beej's Guide to Unix IPC Ważniak – laboratorium z systemów operacyjnych Arkadiusz Chrobot: Wykład: Systemy Operacyjne. Katedra Informatyki Politechniki Świętokrzyskiej Wojciech Kwedlo: Wykład: Systemy operacyjne Wydział Informatyki, Politechnika Białostocka


Pobierz ppt "Systemy operacyjne Wykład 7 Synchronizacja procesów i wątków dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki"

Podobne prezentacje


Reklamy Google