• Nie Znaleziono Wyników

SYSTEMY OPERACYJNE

N/A
N/A
Protected

Academic year: 2021

Share "SYSTEMY OPERACYJNE"

Copied!
60
0
0

Pełen tekst

(1)

SYSTEMY OPERACYJNE

dr. hab. Vitaliy Yakovyna

yakovyna@matman.uwm.edu.pl http://wmii.uwm.edu.pl/~yakovyna/

UNIWERSYTET WARMIŃSKO-MAZURSKI W OLSZTYNIE

Wydział Matematyki i Informatyki

(2)

SYNCHRONIZACJA

PROCESÓW

(3)

Narzędzia Synchronizacji.

Podstawy

(4)

Procesy Współpracujące (Przypomnienie)

• Proces współpracujący może wpływać na inne procesy wykonywane w systemie

• Procesy współpracujące mogą albo bezpośrednio współdzielić logiczną przestrzeń adresową

(zarówno kod, jak i dane) lub mogą mieć możliwość udostępniania danych poprzez pamięć

współdzieloną lub przekazywanie wiadomości

• Jednoczesny dostęp do udostępnionych danych może powodować niespójność danych

(5)

Problem Producenta i

Konsumenta. Ograniczony Bufor

Producer process:

while (true) {

while (count == BUFFER SIZE)

;buffer[in] = next_produced;

in = (in + 1) % BUFFER SIZE;

count++;

}

Consumer process:

while (true) {

while (count == 0)

;next_consumed = buffer[out];

out = (out + 1) % BUFFER SIZE;

count--;

}

(6)

Przeplatanie (Interleaving)

• count++ :

register1 = count

register1 = register1 + 1 count = register1

• count-- :

register2 = count

register2 = register2 - 1 count = register2

• Treść rejestrów jest zapisywana i przywracana przez moduł obsługi przerwań

(7)

Przeplatanie

• Współbieżne wykonanie: instrukcje niższego

poziomu są przeplatane w dowolnej kolejności (ale kolejność w każdej instrukcji wysokiego poziomu jest zachowana)

T0: producer wykonuje register1 = count {register1 = 5}

T1: producer wykonuje register1 = register1 + 1 {register1 = 6}

T2: consumer wykonuje register2 = count {register2 = 5}

T3: consumer wykonuje register2 = register2 - 1 {register2 = 4}

T4: producer wykonuje count = register1 {count = 6}

T5: consumer wykonuje count = register2 {count = 4}

(8)

Warunki Wyścigu (Race Condition)

• Warunek wyścigu – sytuacja, w której kilka

procesów współbieżnie uzyskuje dostęp do tych samych danych i manipuluje nimi, a wynik

wykonania zależy od kolejności, w której odbywał się dostęp

• Musimy zapewnić aby tylko jeden proces mógł

jednocześnie manipulować udostępnionymi danymi

• Współpracujące procesy muszą być w pewien sposób zsynchronizowane i skoordynowane

(9)

Narzędzia Synchronizacji.

Problem Sekcji Krytycznej

(10)

Problem Sekcji Krytycznej

• Sekcja krytyczna to segment kodu, w którym

proces może uzyskiwać dostęp i aktualizować dane, które są współużytkowane z co najmniej jednym

innym procesem

• Gdy jeden proces jest wykonywany w sekcji krytycznej, żaden inny proces nie może być wykonywany we własnej sekcji krytycznej

• Problemem sekcji krytycznej jest zaprojektowanie protokołu, którego procesy mogą użyć do

zsynchronizowania swojej działalności w celu wspólnego udostępniania danych

(11)

Ogólna Struktura Procesu

while (true) {

entry_section

critical_section exit_section

remainder_section }

(12)

Problem Sekcji Krytycznej:

Wymagania do Rozwiązania

1. Wzajemne wykluczanie. Jeśli proces Pi jest wykonywany w sekcji krytycznej, wówczas żadne inne procesy nie mogą być wykonywane w sekcjach krytycznych.

2. Postęp. Jeśli żaden proces nie jest wykonywany w sekcji

krytycznej, a niektóre procesy chcą wejść w sekcje krytyczne, wówczas tylko te procesy, które nie są wykonywane w

pozostałych sekcjach, mogą brać udział w podejmowaniu decyzji, kto następny wejdzie w sekcję krytyczną; wybór ten nie może trwać nieskończone.

3. Ograniczone czekanie. Istnieje ograniczenie liczby razy, w których inne procesy mogą wchodzić do swoich sekcji

krytycznych po tym, jak proces wnioskował o wejście do swojej sekcji krytycznej i przed spełnieniem tego żądania.

(13)

Wyłączanie Przerwań

• Problem sekcji krytycznej można rozwiązać po prostu w środowisku jednordzeniowym, jeśli

możemy zapobiec wystąpieniu przerwań podczas modyfikowania udostępnionej zmiennej

• Wyłączanie przerwań nie jest tak wykonalne w środowisku wieloprocesorowym:

• czasochłonne (wiadomość jest przekazywana do wszystkich procesorów);

• wpływa na zegar systemu (aktualizowany przez przerwania)

(14)

Jądra Wywłaszczeniowe i Niewywłaszczeniowe

• To są dwa ogólne podejścia do obsługi krytycznych sekcji w systemach operacyjnych

• Jądro wywłaszczeniowe pozwala na wywłaszczenie procesu działającego w trybie jądra

• Jądro niewywłaszczeniowe nie pozwala na

wywłaszczenie procesu działającego w trybie jądra;

proces w trybie jądra będzie działał, dopóki nie wyjdzie z trybu jądra, nie zablokuje się lub

dobrowolnie nie opuści kontroli nad procesorem

(15)

Jądra Wywłaszczeniowe i Niewywłaszczeniowe

• Jądro niewywłaszczeniowe:

ozasadniczo wolne od warunków wyścigu w strukturach danych jądra

• Jądro wywłaszczeniowe:

omusi być starannie zaprojektowane, aby zapewnić, że wspólne dane jądra są wolne od warunków wyścigu ojest szczególnie trudne do zaprojektowania dla

architektury SMP

omoże być bardziej responsywne

ojest bardziej odpowiednie do programowania w czasie rzeczywistym

(16)

Narzędzia Synchronizacji.

Rozwiązanie Petersona

(17)

Struktura Procesu P

i

w Rozwiązaniu Zmiennej Blokującej

int lock = 0;

while (true) {

while (lock)

;

lock = 1;

/* critical section */

lock = 0;

/*remainder section */

}

(18)

Struktura Procesu P

i

w Rozwiązaniu Ścisłej Alternacji

int turn = 0;

while (true) {

while (turn != i)

;

/* critical section */

turn = 1 - i;

/*remainder section */

}

(19)

Struktura Procesu P

i

w Rozwiązaniu Tablicy Flag

boolean flag[2] = {false, false};

while (true) {

flag[i] = true;

while (flag[1 - i])

;

/* critical section */

flag[i] = false;

/*remainder section */

}

(20)

Struktura Procesu P

i

w Rozwiązaniu Petersona

int turn;

boolean flag[2];

while (true) {

flag[i] = true;

turn = j;

while (flag[j] && turn == j)

;/* critical section */

flag[i] = false;

/*remainder section */

}

(21)

Rozwiązanie Petersona

• Klasyczne rozwiązanie programowe problemu sekcji krytycznej

• Aby poprawić wydajność systemu, procesory lub kompilatory mogą zmieniać kolejność operacji odczytu i zapisu, które nie są zależne → nie ma

gwarancji, że rozwiązanie Petersona będzie działać poprawnie na nowoczesnych architekturach

komputerowych

(22)

Zmiana Kolejności Odczytu/Zapisu

boolean flag = false;

int x = 0;

Thread 1:

while (!flag)

;

print x; /*reordering in Thread 2 OR loading x value before the flag in Thread 1 → will print 0*/

Thread 2:

x = 100;

flag = true; //may be assigned before x

(23)

Skutki Zmiany Kolejności Instrukcji

w Rozwiązaniu Petersona

(24)

Narzędzia Synchronizacji.

Sprzętowa Obsługa

Synchronizacji

(25)

Modele Pamięci

• Model pamięci – co będzie zapewnione aplikacji przez pamięć

• Modele pamięci różnią się w zależności od typu procesora

• Kategorie modeli pamięci:

1) Mocno uporządkowane, modyfikacja pamięci na jednym procesorze jest natychmiast widoczna dla wszystkich innych procesorów

2) Słabo uporządkowane, modyfikacja pamięci na jednym procesorze może nie być natychmiast widoczna dla

innych procesorów

(26)

Bariery Pamięci

• Architektury komputerowe zapewniają instrukcje

(bariery pamięci), które mogą wymusić propagowanie wszelkich zmian w pamięci do wszystkich innych

procesorów

• Instrukcja bariery pamięci → system zapewnia, że

wszystkie operacje ładowania (load) i przechowywania (store) zostaną zakończone przed kolejnymi operacjami ładowania lub przechowywania

• Bariery pamięci są uważane za operacje na bardzo niskim poziomie i zwykle są używane tylko przez programistów jądra

(27)

Bariery Pamięci

• Thread 1:

while (!flag)

memory_barrier();

print x;

• Thread 2:

x = 100;

memory_barrier();

flag = true;

(28)

Bariery Pamięci w Rozwiązaniu Petersona

int turn;

boolean flag[2];

while (true) {

flag[i] = true;

memory_barrier();

turn = j;

while (flag[j] && turn == j)

;/* critical section */

flag[i] = false;

/*remainder section */

}

(29)

Instrukcje Sprzętowe

• Wiele nowoczesnych systemów komputerowych udostępnia specjalne instrukcje sprzętowe, które

pozwalają testować i modyfikować zawartość słowa, albo zamieniać zawartość dwóch słów atomowo

• Na architekturach Intel x86 instrukcja cmpxchg języka asemblera służy do implementacji funkcji

compare_and_swap(). Aby wymusić wykonanie atomowe, prefiks lock służy do blokowania

magistrali:

lock cmpxchg <destination>, <source>

(30)

Instrukcje Test_and_set() oraz compare_and_swap()

boolean test_and_set(boolean *target) { boolean rv = *target;

*target = true;

return rv;

}

int compare_and_swap(int *value, int expected, int new_value) {

int temp = *value;

if (*value == expected)

*value = new value;

return temp;

}

(31)

Implementacja wzajemnego

wykluczenia za pomocą test_and_set()

do {

while (test_and_set(&lock))

; /* do nothing */

/* critical section */

lock = false;

/* remainder section */

} while (true);

(32)

Zmienne Atomowe

• Zmienne atomowe zapewniają operacje atomowe na podstawowych typach danych, takich jak liczby

całkowite i logiczne

• Większość systemów obsługujących zmienne atomowe zapewnia specjalne atomowe typy danych, a także

funkcje dostępu do atomowych zmiennych i manipulowania nimi

• Funkcje te są często implementowane przez operację compare_and_swap()

• Zmienne atomowe są powszechnie stosowane w aplikacjach współbieżnych, chociaż ich użycie jest często ograniczone do pojedynczych aktualizacji udostępnionych danych, takich jak liczniki

(33)

Narzędzia Synchronizacji.

Blokady

(34)

Blokada Mutex

• Rozwiązania sprzętowe problemu sekcji krytycznej są skomplikowane, a także ogólnie są niedostępne dla programistów aplikacji

• Projektanci systemów operacyjnych tworzą narzędzia programowe wyższego poziomu

• Najprostszym z tych narzędzi jest blokada mutex

• Blokady mutex można wdrożyć za pomocą operacji compare_and_swap()

(35)

Blokada Mutex

while (true) { acquire_lock

critical_section

release_lock

remainder_section }

(36)

Spin-Lock (Wirująca Blokada)

• Oczekiwanie na zwolnienie blokady polega na ciągłym badaniu jej stanu

acquire() {

while (!available)

; /*aktywne oczekiwanie*/

available = false;

}

release() {

available = true;

}

(37)

Spin-Lock

• Główna wada – aktywne oczekiwanie (problem

odwracania priorytetów; marnowanie cykli procesora)

• Zaleta – brak przełączania kontekstu, gdy proces musi czekać na blokadę

• Jeśli blokada ma być utrzymywana przez krótki czas (mniej niż dwa przełączania kontekstu), jeden wątek może „wirować się” na jednym rdzeniu procesorowym, podczas gdy inny wątek wykonuje swoją sekcję

krytyczną na innym rdzeniu

• W nowoczesnych wielordzeniowych systemach

komputerowych blokady wirujące (spin-lock) są szeroko stosowane w wielu systemach operacyjnych

(38)

Narzędzia Synchronizacji.

Semafory

(39)

Semafory

• Edsger W. Dijkstra, 1962 lub 1963

• Semafor S jest zmienną całkowitą, która oprócz

inicjalizacji jest dostępna tylko przez dwie operacje atomowe: wait() oraz signal()

• Semafor binarny może przyjmować wartości całkowite ze zbioru {0, 1}

• Semafor zliczający – również większe niż 1

(40)

Semafory

• Definicja funkcji wait() wait(S) {

while (S <= 0)

; //aktywne oczekiwanie S--;

}

• Definicja funkcji signal() signal(S) {

S++;

}

(41)

Wykorzystanie Semaforów (Synchronizacja)

• Instrukcja S2 musi zostać wykonana dopiero po zakończeniu S1

• Proces P1 S1;

signal(synch);

• Proces P2

wait(synch);

S2;

(42)

Wykorzystanie Semaforów (Producent – Konsument)

item buffer[N];

int in = 0;

int out = 0;

Semaphore mutex = 1;

Semaphore empty = 0;

Semaphore full = N;

(43)

Wykorzystanie Semaforów.

Proces Producenta

item next_produced;

while (true) {

/*produce an item*/

wait(&full);

wait(&mutex);

buffer[in] = next_produced;

in = (in + 1) % N;

signal(&mutex);

signal(&empty);

}

(44)

Wykorzystanie Semaforów.

Proces Konsumenta

while (true) { wait(&empty);

wait(&mutex);

next_consumed = buffer[out];

out = (out + 1) % N;

signal(&mutex);

signal(&full);

/*consume item*/

}

(45)

Implementacja Semaforów

• Implementacja blokady mutex (spin-lock) cierpi z powodu aktywnego oczekiwania

• Aktywne oczekiwanie → Zawieszenie

• Operacja zawieszenia umieszcza proces w kolejce oczekiwania powiązanej z semaforem, a stan

procesu jest przełączany na „oczekujący”

• Proces zawieszony, oczekujący na semaforze S, powinien zostać zrestartowany, gdy jakiś inny proces wykonuje operację signal()

(46)

Narzędzia Synchronizacji.

Żywotność

(47)

Żywotność

• Jedną z konsekwencji korzystania z narzędzi

synchronizacji do koordynowania dostępu do sekcji krytycznych jest możliwość, że proces próbujący

wejść do sekcji krytycznej będzie czekać w

nieskończoność – „niepowodzenie żywotności”

• Żywotność odnosi się do zestawu właściwości, które musi spełniać system, aby zapewnić postęp procesów w cyklu ich wykonywania

(48)

Zakleszczenie

• Zestaw procesów jest zablokowany, gdy każdy

proces w zestawie czeka na zdarzenie, które może być spowodowane tylko przez inny proces w

zestawie

P0 P1

wait(S); wait(Q);

wait(Q); wait(S);

… …

signal(S); signal(Q);

signal(Q); signal(S);

(49)

Odwrócenie Priorytetów

• Proces o wyższym priorytecie musi czytać lub modyfikować dane jądra, do których obecnie uzyskuje dostęp proces o niższym priorytecie

• Dane jądra są zwykle chronione za pomocą blokady

→ proces o wyższym priorytecie będzie musiał

czekać na zakończenie operacji z danymi procesem o niższym priorytecie

• Sytuacja staje się bardziej skomplikowana, jeśli

proces o niższym priorytecie zostanie wywłaszczony na korzyść procesu o wyższym priorytecie

(50)

Protokół Dziedziczenia Priorytetów

• Zazwyczaj odwrócenia priorytetów unika się

poprzez implementację protokołu dziedziczenia priorytetów

• Wszystkie procesy uzyskujące dostęp do zasobów potrzebnych procesom o wyższym priorytecie,

dziedziczą wyższy priorytet, dopóki nie zostaną zakończone operacje z danymi zasobami

• Po zakończeniu ich priorytety powracają do pierwotnych wartości

(51)

Narzędzia Synchronizacji.

Ocena

(52)

Podejście CAS vs. Blokady

• Podejście CAS to podejście optymistyczne – najpierw optymistycznie aktualizujesz zmienną, a następnie używasz wykrywania kolizji, aby sprawdzić, czy inny wątek współbieżnie nie aktualizuje zmienną

• Natomiast blokada jest uważana za strategię

pesymistyczną; zakładasz, że inny wątek współbieżnie aktualizuje zmienną, więc pesymistycznie uzyskujesz blokadę przed dokonaniem jakichkolwiek aktualizacji

(53)

Wydajność

• Brak rywalizacji. Chociaż obie opcje są na ogół szybkie, podejście CAS będzie nieco szybsze niż tradycyjna synchronizacja

• Umiarkowana rywalizacja. Podejście CAS będzie szybsze niż tradycyjna synchronizacja

• Wysoka rywalizacja. Tradycyjna synchronizacja będzie szybsza niż synchronizacja oparta na CAS

(54)

Wydajność Systemu

• Atomowe liczby całkowite są ogólnie bardziej

stosowne niż blokady dla pojedynczych aktualizacji wspólnych zmiennych, takich jak liczniki

• Blokady są prostsze i są lepsze niż semafory binarne do ochrony dostępu do krytycznej sekcji

• W przypadku niektórych zastosowań (dostęp do skończonej liczby zasobów) semafor zliczający jest bardziej odpowiedni niż blokada

(55)

Przyszłe Prace

• Trwają badania nad opracowaniem skalowalnych, wydajnych narzędzi, które spełniają wymagania programowania współbieżnego:

oProjektowanie kompilatorów generujących bardziej wydajny kod

oOpracowywanie języków wspierających programowanie współbieżnie (C++ 11)

oZwiększenie wydajności istniejących bibliotek i interfejsów API

(56)

Narzędzia Synchronizacji.

Streszczenie

(57)

Streszczenie (1)

• Warunek wyścigu występuje, gdy procesy mają współbieżny dostęp do udostępnionych danych, a wynik zależy od kolejności, w jakiej występuje

dostęp. Warunki wyścigu mogą spowodować uszkodzenie wartości wspólnych danych.

• Sekcja krytyczna to sekcja kodu, w której odbywa się manipulowanie udostępnionymi danymi i

możliwe nastąpienie warunków wyścigu.

Problemem sekcji krytycznej jest zaprojektowanie protokołu dla synchronizacji aktywności procesów w celu wspólnego udostępniania danych.

(58)

Streszczenie (2)

• Rozwiązanie problemu sekcji krytycznej musi spełniać następujące trzy wymagania: (1)

wzajemne wykluczanie, (2) postęp, oraz (3) ograniczone czekanie. Wzajemne wykluczenie

zapewnia, że tylko jeden proces na raz jest aktywny w swojej krytycznej sekcji. Postęp zapewnia, że

programy wspólnie określą, który proces wejdzie następnie w jego krytyczną sekcję. Ograniczone

oczekiwanie ogranicza czas oczekiwania procesu na przejście do jego krytycznej sekcji.

(59)

Streszczenie (3)

• Rozwiązania programowe dla problemu sekcji krytycznej, takie jak rozwiązanie Petersona, nie działają dobrze na nowoczesnych architekturach komputerowych.

• Wsparcie sprzętowe dla problemu sekcji krytycznej obejmuje bariery pamięci; instrukcje sprzętowe,

takie jak compare-and-swap; i zmienne atomowe.

• Blokada zapewnia wzajemne wykluczenie,

wymagając, aby proces uzyskał blokadę przed

wejściem do sekcji krytycznej i zwolnił blokadę przy wyjściu z sekcji krytycznej.

(60)

Streszczenie (4)

• Semafory, podobnie jak blokady mutex, mogą

służyć do wzajemnego wykluczenia. Jednak podczas gdy blokada mutex ma wartość binarną, która

wskazuje, czy blokada jest dostępna, czy nie,

semafor ma wartość całkowitą i dlatego może być używany do rozwiązywania różnych problemów z synchronizacją.

• Rozwiązania problemu sekcji krytycznej mogą cierpieć z powodu problemów z żywotnością, w tym zakleszczenia.

Cytaty

Powiązane dokumenty

Celem kursu jest zapoznanie Studentów z problematyką dotyczącą infrastruktury krytycznej państwa, charakterystyki jej systemów oraz metod ochrony, a także roli

W związku z inicjatywą adwokatów z Iz­ by warszawskiej, stanowiskiem NRA, życz­ liwym przyjęciem tego stanowiska przez przedstawiciela Rady Państwa, a także w

(K’) Zatem to, co mówi X powinno być akceptowane jako bardziej wiarygodne (odrzucane jako mniej wiarygodne) 6.. W obu tych schematach podstawą dla uznania konkluzji jest

Pierwszy jest z 7 marca: „W składzie szkła, porcelany, wyrobów galanteryjnych i tokarskich Józefa Cybulskiego przy ulicy Dużej odbywać się będzie codziennie

(Z całą pewnością nie jest łatwo mu przypisać wprost wyrażoną intencję immunizowania własnej teorii krytycznej przed argumentami jakiego ­ kolwiek rodzaju, chociaż -

Jeśli chcemy upewnić się, że sekwencja operacji jest atomowa należy użyć synchronizacji

Jeżeli pętla byłaby umieszczona również wewnątrz sekcji krytycznej to w zależności od ich umiejscowienia (względem miejsca modyfikacji zmiennej będącej warunkiem pętli)

W sekcji krytycznej może być tylko jeden proces to znaczy instrukcje z sekcji krytycznej nie mogą być przeplatane.. Nie można czynić żadnych założeń co do względnych szybko