wykład 3 - MiNI PW - Politechnika Warszawska

Transkrypt

wykład 3 - MiNI PW - Politechnika Warszawska
Programowanie Równoległe i Rozproszone
Wykład 3
Programowanie Równoległe
i
Rozproszone
Lucjan Stapp
Wydział Matematyki i Nauk Informacyjnych
Politechnika Warszawska
([email protected])
1/75
PRiR Wykład 3
Synchronizacja
Trzy podstawowe zadania programów równoległych
to:
1. Jednoczesna praca procesorów (równoległość
wykonania)
2. Wymiana informacji (komunikacja między
procesowa)
3. Wymuszenie na procesorach ustalenia jednej
wartości dla zmiennej albo czasu
rozpoczęcia i zakończenia
(synchronizacja)
2/75
PRiR Wykład 3
Synchronizacja
1. Równoległość:
Wybór między SIMD a MIMD
3/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
1
Programowanie Równoległe i Rozproszone
Wykład 3
Synchronizacja
2. Komunikacja międzyprocesorowa
(międzyprocesowa)
Ani ludzie ani komputery nie mogą się komunikować bez
ustalenia pewnego zbioru nazw.
Architektura z pamięcią dzieloną vs multikomputery
Problem komunikacji można rozwiązać na różne sposoby
1. architektura pamięci dzielonej
• szyny
• połączenie typu crossbar
• połączenie typu multistage
2. dla maszyn z pamięcią rozproszoną
• pierścienie
• drzewa binarne
• dwu-wymiarowe tablice procesorów
• hiperkostka (hypercube)
Architektury te były prezentowane na pierwszym wykładzie
4/75
PRiR Wykład 3
Synchronizacja
Synchronizacja
Synchronizacja odnosi się do potrzeby ustalenia jednej
wartości dla zmiennej przez dwa (lub więcej)
procesory.
Dwa podstawowe problemy to:
1. wzajemne wykluczanie
2. spójność pamięci
Wzajemne wykluczanie (ang. mutual exclusion) –
zezwalanie dokładnie jednemu procesorowi na
dostęp do danego miejsca w pamięci w tym samym
czasie.
5/75
PRiR Wykład 3
Synchronizacja
Przykład 1
Proc_1:
I_11:
x←1
Proc_2:
I_21:
x←2
Wartość początkowa : x=0
6/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
2
Programowanie Równoległe i Rozproszone
Wykład 3
Synchronizacja
Przykład 1 cd
Możliwe scenariusze
wykonania:
Time
Proc_1
Proc_2 x
0
1
x←2
2
x←1
Time
Proc_1 Proc_2 x
0
x←2
2
x←1
1
Stąd możliwe wartości x to 1 lub 2.
7/75
PRiR Wykład 3
Synchronizacja
Przykład 2.
Proc_1:
y←x+1;
x ← y;
z←z + y;
Proc_2:
y←x+1;
x←y;
z←z + y;
Początkowe wartości : x=0, y=0, z=0
8/75
PRiR Wykład 3
Synchronizacja
Time
Przykład 2 cd.
Możliwe scenariusze
wykonania:
Proc_1
Proc_2
x
y
z
0
0
0
y←x+1
0
1
0
x←y
1
1
0
z←z + y
1
1
1
1
2
1
y←x+1
Time Proc_1
Proc_2
y←x+1
y←x+1
x←y
x←y
z←z + y
z←z + y
x
y
z
0
0
0
x←y
2
2
1
z←z + y
2
2
3
Time Proc_1
Proc_2
x
y
z
0
0
0
0
0
1
0
y←x+1
0
1
0
1
0
x←y
1
1
0
1
1
0
1
2
0
1
1
0
1
1
1
1
1
2
y←x+1
z←z + y
9/75
Przygotował: Lucjan Stapp
x←y
2
2
2
z←z + y
2
1
4
PRiR Wykład 3
3
Programowanie Równoległe i Rozproszone
Wykład 3
Synchronizacja
Przykład 2 cd.
Możliwe wartości końcowe:
x
y
z
2
2
3
1
1
2
2
1
4
10/75
PRiR Wykład 3
Synchronizacja
Wniosek:
Wzajemne wykluczanie NIE wystarcza, aby
zapewnić poprawne wykonanie programu
równolegle wykonywanego.
11/75
PRiR Wykład 3
Definicje
Proces – sekwencyjna część programu równolegle
wykonywanego (równoległego), wykonywana na
jednym procesorze.
Liczba procesów może być większa niż liczba
procesorów w systemie.
(Rozwiązanie powyższego problemu zostanie
podane w przyszłości).
Sekcja krytyczna – sposób na poprawną
komunikację.
Co najwyżej jeden proces może pracować w
sekcji krytycznej, wykorzystując w tym
samym czasie wspólne zasoby (np. zmienne)
12/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
4
Programowanie Równoległe i Rozproszone
Wykład 3
Synchronizacja
Przykład 2. cd
Proc_1:
critical section
y←x+1;
x ← y;
z←z + y;
end of critical section
Proc_2:
critical section
y←x+1;
x←y;
z←z + y;
end of critical section
Początkowe wartości: x=0, y=0, z=0
13/75
PRiR Wykład 3
Synchronizacja
Przykład 2. cd
Możliwe scenariusze
wykonania:
Time
Proc_1
Proc_2
x
y
z
0
0
0
y←x+1
0
1
0
x←y
1
1
0
z←z + y
1
1
1
1
2
1
y←x+1
Time
Proc_1
x←y
2
2
1
z←z + y
2
2
3
x
y
z
0
0
0
y←x+1
0
1
0
x←y
1
1
0
z←z + y
1
1
1
y←x+1
1
2
1
x←y
2
2
1
z←z + y
2
2
3
14/75
Proc_2
PRiR Wykład 3
Synchronizacja
Example 2 - cont.
Jedyny możliwy wynik:
x
y
z
2
2
3
15/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
5
Programowanie Równoległe i Rozproszone
Wykład 3
Wniosek
Komunikacja między procesami
jest oparta na
wzajemnym wykluczaniu
się sekcji krytycznych
16/75
PRiR Wykład 3
Pierwszy (podstawowy) schemat
komunikacji
Przykład 4 - komunikacja
Proc_1:
cycle
instrukcja_1_A;
wysyłanie informacji;
instrukcja _1_b;
end_of_cycle
Proc_2:
cycle
instrukcja _2_A;
odbieranie informacji;
instrukcja _2_B;
end_of_cycle
17/75
PRiR Wykład 3
Pierwszy schemat komunikacji
Example 4a (Producent - konsument )
Proc_1:
cycle
instruction_1_A;
critical_section
wysyłanie informacji do pustego bufora;
(zapis do pustego bufora);
end_of_critical_section;
end_of_cycle;
Proc_2:
cycle
instruction_2_A;
critical_section
odbieranie informacji z niepustego bufora (czytanie z
bufora);
end_of_critical_section;
end_of_cycle;
18/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
6
Programowanie Równoległe i Rozproszone
Wykład 3
Drugi (podstawowy) schemat komunikacji
Drugi podstawowy schemat wykorzystywany
do komunikacji – jest używany głównie w
systemach rozproszonych – handshaking
(ang. uścisk dłoni);
19/75
PRiR Wykład 3
Drugi schemat komunikacji
Cycle
Cycle
Instruction_1_A;
critical_section;
wysłanie sygnału;
end_of_critical_section;
Instruction_2_A;
critical_section;
czekanie na sygnał;
wysłanie odpowiedzi;
end_of_critical_section;
critical_section;
czekanie na odpowiedź;
end_of_critical_section;
critical_section;
pisanie (wysyłanie) danych;
end_of_critical_section;
critical_section;
czekanie na end_signal;
end_of_critical_section;
end_of_cycle;
wait;
critical_section;
odbieranie danych;
wysłanie end_signal;
end_of_critical_section;
end_of_cycle;
20/75
PRiR Wykład 3
Przykład 5
Proc_1:
cycle
instruction_1_A;
critical_section
czekaj_dopóki_bufor_2_jest_pusty;
end_of_critical_section;
critical_section
czytaj_z_bufor_2;
end_of_critical_section;
instruction_1_b;
critical_section
czekaj_dopóki_bufor_1_jest_pełny;
pisz_do_bufor_1;
end_of_critical_section;
end_of_cycle;
Proc_2:
cycle
instruction_2_A;
critical_section
czekaj_dopóki_bufor_1_jest_pusty;
end_of_critical_section;
critical_section
czytaj_z_bufor_1;
end_of_critical_section
instruction_2_B;
critical_section
czekaj_dopóki_bufor_2_jest_pełny;
pisz_do_bufor_2;
end_of_critical_section;
end_of_cycle;
21/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
7
Programowanie Równoległe i Rozproszone
Wykład 3
Deadlock
W powyższej sytuacji oba procesy będą czekały w
nieskończoność na dane:
• Proc_1 na dane z bufora_2
• Proc_2 na dane z bufora_1
Powyższa sytuacja to tzw. zakleszczenie (ang.
deadlock).
Zakleszczenie to ZAWSZE krytyczny błąd
programisty.
22/75
PRiR Wykład 3
SEMAFORY
Teraz zademonstrujemy narzędzia do zarządzania
sekcją krytyczną.
Wymagania stawiane rozwiązaniom:
1. Symetryczność i równość procesów.
2. Niezależne od prędkości procesów.
3. Skończony czas rozwiązywania konfliktów.
4. Niezależne czynności poza sekcją krytyczną.
23/75
PRiR Wykład 3
SEMAFORY
SYNCHRONIZACJA PRZEZ ZMIENNĄ CAŁKOWITĄ
(LICZNIK)
int x= 0;
/* x = 0 gdy nie ma żadnego procesu w sekcji krytycznej
x = 1 gdy jest jakiś proces w sekcji krytycznej */
process:: P;
{
while(1)
{
instructions_A;
while (!x)
{
x++;
if ( x<> 1 )
{
x--;
loop;
}
}
/* teraz sekcja krytyczna */
/* po sekcji krytycznej */
x --;
} /*while*/
} /* P */
24/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
8
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
SYNCHRONIZACJA PRZEZ ZMIENNĄ CAŁKOWITĄ
(LICZNIK)
Powyższe rozwiązanie jest błędne:
Z dwoma procesami pracującymi krok po kroku,
x może przyjąć wartość 2.
Żaden proces nie wejdzie do sekcji krytycznej.
25/75
PRiR Wykład 3
SEMAFORY
SYNCHRONIZACJA PRZEZ ZMIENNE LOKALNE
int x:= 0;
/* x = 0 gdy nie ma żadnego procesu w sekcji krytycznej
x = 1 gdy jest jakiś proces w sekcji krytycznej */
process :: P;
{ int y = 1;
{ while(1)
{ instructions_A;
x ←→y;
/* operacja atomowa – zamiana wartości */
while (y) x ←→y;
/* teraz sekcja krytyczna */
/* po sekcji krytycznej */
x ←→y;
} /*while*/
};
} /* P */
Wniosek: aktywne czekanie (busy waiting)
26/75
PRiR Wykład 3
SEMAFORY
SYNCHRONIZACJA PRZEZ SEMAFORY
(Semafory Dijkstry)
Semafor: specjalna zmienna skojarzona z sekcją
krytyczną.
Są dwie atomowe (niepodzielne) operacje na
semaforze s:
• P(s):
opuść semafor s
(=czekaj na semaforze s)
Wait (s)
• V(s):
podnieś semafor s
(= sygnalizuj na semaforze s)
Signal (s)
27/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
9
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
Zarys kodu semafora::
class semaphore:: public s;
{ int s;
SET qs;
/* zbiór czekających procesów */
void Wait(s)
{ if (s=< 0)
dodaj_proces_do_qs ;
else
s--;
};
void Signal(s)
{ if (not_empty(qs) )
aktywuj_jakiś_proces_z_qs;
else
s++;
}
}
28/75
PRiR Wykład 3
SEMAFORY
Są 3 stany semafora:
1. s > 0
2. s = 0 i qs jest pusty
3. s = 0 i qs nie jest pusty.
Wait(s):
s=0
Tak
Nie
“uśpij” proces w qs
s-29/75
PRiR Wykład 3
SEMAFORY
Signal(s):
s=0
Tak
Nie
s++
qs jest pusty
Tak
s++
Nie
aktywuj jakiś proces z qs
Ponieważ stan
s> 0 i qs niepusta jest niemożliwy
upraszczamy Signal(s)
(zaznaczona część powyższej ilustracji).
30/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
10
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
Semafory spełniają nasze wymagania.
1. Symetryczność i równość procesów.
2. Niezależne od prędkości procesów.
3. Skończony czas rozwiązywania konfliktów.
4. Niezależne od czynności poza sekcją krytyczną.
31/75
PRiR Wykład 3
SEMAFORY
Dostęp do sekcji krytycznej - typowy schemat
semaphore w = 1;
process:: P;
{while(1)
{
instruction_A;
Wait(w);
/* opuść semafor w */
/* wejście do sekcji krytycznej*/
/* sekcja krytyczna */
/*wyjście z sekcji krytycznej */
Signal(w);
/*podnieś semafor w */
} /*while*/
} /* P */;
32/75
PRiR Wykład 3
SEMAFORY
Producent - konsument z jednoelementowym buforem
33/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
11
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
buffer buf;
semaphore full, empty = 0, 1;
process producer;
Product S;
Product production()
{
.....;}
void main()
{while(1)
{
S= production ();
Wait(empty);
/*czekanie na pusty bufor */
buf=S;
Signal(full);
/* sygnalizuj, że coś jest w
buforze */
}
};
process consumer;
Void consumption( product S)
{
.....;}
void main()
{ product S;
while(1)
{
Wait(full);
/* czekaj aż coś będzie w buforze */
S=buf;
Signal(empty);
/*sygnalizuj, że bufor jest pusty */
consumption (S);
}
}
34/75
PRiR Wykład 3
SEMAFORY
Dlaczego potrzeba 2 semaforów (full oraz empty)?
Czy zawsze full + empty == 1 ?
35/75
PRiR Wykład 3
SEMAFORY
Schemat producent - konsument:
jednoelementowy bufor,
m producentów, n konsumentów
Kod dla producenta i konsumenta nie ulega zmianie.
36/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
12
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
Schemat producent - konsument
każdy proces jest jednocześnie producentem i
konsumentem
37/75
PRiR Wykład 3
SEMAFORY
buffer buf1, buf2;
semaphore full1,empty1,full2,empty2 = 0,1,0,1;
/*dla każdego bufora potrzebujemy dwóch semaforów*/
process::P1;
product S,C;
void main()
{while(1)
{
/* produkcja do buf2 */
S= production();
Wait(empty2);
buf2 = S;
Signal(full2);
/*pobranie z buf1 */
Wait(full1);
C=buf1;
Signal(empty1);
Consumption (C);
};
};
process::P2;
Product S,C;
void main()
{while(1)
{
/* produkcja do buf1 */
S= production();
Wait(empty1);
buf1 =S;
Signal(full1);
/* pobranie z buf2 */
Wait(full2);
C=buf2 ;
Signal(empty2);
Consumption (C);
};
};
38/75
PRiR Wykład 3
SEMAFORY
Schemat producent konsument
z nieskończonym buforem
39/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
13
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
buffer buf [ ];
int first_free = 1;
/* pierwsza pusta komórka w buforze */
int last_occ = 1;
/* ostatnia komórka w buforze z nieprzeczytanymi informacjami */
semaphore full, wp, wc = 0,1,1;
/* full do sprawdzenia czy czytanie jest możliwe;
full jest równe liczbie pełnych (nieprzeczytanych) komórek w buforze;
bufor jest nieskończony,
dlatego dodanie do bufora jest zawsze możliwe */
/* wp dla wzajemnego wykluczania się producentów */
/* wc dla wzajemnego wykluczania się konsumentów */
40/75
PRiR Wykład 3
SEMAFORY
process :: producer;
{ product S;
void main()
{ while(1)
{ S= production();
Wait(wp);
/* opuść semafor wp, aby zapewnić
dostęp do bufora na wyłączność */
buf [first_free] = S;
/* wstaw produkt na pierwsze wolne
miejsce w buforze */
first_free ++ ;
Signal(full);
/* podnieś semafor wp, aby udostępnić
dostęp innym producentom do bufora */
Signal(wp);
};
}; };
process :: consumer;
{ product S;
void main()
{ while(1)
{
Wait(full);
/* konsumpcja jest możliwa tylko gdy coś
jest w buforze*/
Wait(wc);
/* opuść semafor wc, aby uzyskać dostęp
do bufora na wyłączność */
S=buf[last_occ];
last_occ++;
Signal(wc);
/* podnieś semafor wc by udostępnić
innym konsumentom dostęp do bufora */
consumption(S);
};
};
};
41/75
PRiR Wykład 3
SEMAFORY BINARNE
Binarny semafor (ang. binary semaphore) ma tylko 2
wartości: 0 i 1.
Zamiast operacji Wait i Signal używamy analogicznych
operacji binarnych:
BWait i BSignal.
42/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
14
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY BINARNE
Producent konsument z nieskończonym buforem i
semaforami binarnymi
Zamiast semafora full powinno się użyć:
• zmienną całkowitą m = liczba pełnych komórek w
buforze
• binarny semafor bfull
• binarny semafor wm pilnujący dostępu do zmiennej m
43/75
PRiR Wykład 3
SEMAFORY BINARNE
buffer buf [ ] ;
int first_free = 1;
/* pierwsza wolna komórka w buforze*/
int last_occ = 1;
/* ostatnia komórka z nieprzeczytanymi informacjami*/
binary semaphore bfull, wp, wc, wm = 0,1,1,1;
/* wm - semafor dostępu do zmiennej m*/
int m = 0;
/* liczba wypełnionych komórek */
44/75
PRiR Wykład 3
SEMAFORY BINARNE
process :: producer;
{ product S;
void main()
{ while(1)
{ S= production();
BWait(wp);
buf [first_free] = S;
first_free ++ ;
BSignal(wp);
/*poniższa sekwencja instrukcji jest
użyta zamiast Signal(full) z
poprzedniego przykładu*/
BWait(wm);
m++;
if (m ==1) BSignal(bfull);
Bsignal(wm);
};
};
};
process :: consumer;
{ product S;
void main()
{ while(1)
{
Bwait(bfull);
/* konsumpcja jest możliwa gdy coś jest w
buforze*/
Bwait(wc);
S=buf[last_occ];
last_occ++;
BSignal(wc);
BWait(wm);
m--;
if (m >0) Bsignal (bfull);
BSignal(wm);
/* jeżeli bufor jest niepusty, musimy otworzyć
semafor binarny bfull */
consumption(S);
};
};
}; 45/75
PRiR Wykład 3
Przygotował: Lucjan Stapp
15
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY BINARNE
Uwaga: Celem powyższego przykładu jest pokazanie, jak
zastąpić semafor zwykły semaforem binarnym;
czasami może to prowadzić do dodatkowych
komplikacji; nie będą one omawiane na niniejszym
wykładzie.
46/75
PRiR Wykład 3
SEMAFORY
Producent konsument ze skończonym buforem
47/75
PRiR Wykład 3
SEMAFORY
Producent - konsument ze skończonym buforem
Nowy semafor empty powinien zostać dodany do
poprzedniego rozwiązania.
Umieszczenie elementu w buforze jest możliwe, gdy
empty (liczba wolnych komórek w buforze) jest
większa niż 0.
W przeciwnym wypadku producent powinien czekać
(w zbiorze na semaforze empty).
48/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
16
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
#define N = ??? /*wielkość bufora */
buffer buf [ ] ;
int first_free = 1;
/* pierwsza wolna komórka w buforze */
int last_occ = 1;
/* ostatnia komórka w buforze z nieprzeczytaną informacją */
semaphore full, empty = 0,N;
binary semaphore wp, wc = 1,1;
49/75
PRiR Wykład 3
SEMAFORY
process :: producer;
{
product S;
void main()
{ while(1)
{ S= production();
Wait(empty);
BWait(wp);
buf [first_free] = S;
first_free=(first_free + 1)%N;
BSignal(wp);
Signal(full);
};
};
};
process :: consumer;
{
product S;
void main()
{ while(1)
{ Wait(full);
BWait(wc);
S=buf[last_occ];
last_occ=(last_occ+1)%N;
BSignal(wc);
Signal(empty);
consumption(S);
};
};
};
50/75
PRiR Wykład 3
SEMAFORY
Problem czytelników i pisarzy
Readers – writers problem
Opis problemu:
• Jest n czytelników, m pisarzy i jedna wspólna
strona;
• Każdy czytelnik czyta informacje ze strony, każdy
pisarz może pisać na stronie;
• Wielu czytelników może naraz czytać dane ze
strony;
• Pisarz zajmuje stronę na wyłączność (żaden inny
proces – pisarz czy czytelnik - nie może używać w
tym czasie strony);
• Nie ma ograniczeń czasowych na czytanie i pisanie,
ale operacje te są skończone.
51/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
17
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
Schemat: czytelnicy i pisarze
52/75
PRiR Wykład 3
SEMAFORY
Readers – writers problem
Rozwiązanie:
Pisarz:
Robi coś;
Chce pisać;
Pisze;
Informuje, że skończył pisać;
Czytelnik:
Robi coś;
Chce czytać;
Czyta;
Informuje, że skończył czytać;
53/75
PRiR Wykład 3
SEMAFORY
int no_of_r;
/* liczba procesów - czytelników aktualnie czytających */
binary semaphore sp, w = 1, 1;
/* w służy do synchronizacji dostępu do no_of_r,
sp służy do synchronizacji dostępu do strony */
54/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
18
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
process :: reader;
void main()
{
while(1)
{
BWait(w);
no_of_r ++;
if (no_of_ r == 1)
BWait(sp);
/* pierwszy czytelnik opuszcza sp */
BSignal(w);
/* czytanie ze strony*/
BWait(w);
no_of_r --;
if (no_of_r == 0)
BSignal(sp);
/* ostatni czytelnik podnosi semafor sp */
BSignal(w);
};
};
process :: writer;
void main()
{
while(1)
{
BWait(sp);
/* każdy piszący proces musi
opuścić semafor sp */
/* pisanie na stronie */
BSignal(sp);
};
};
55/75
PRiR Wykład 3
SEMAFORY
Czytelnicy - pisarze z priorytetem dla pisarzy.
Dodajemy dwa dodatkowe warunki do zadania:
1. Pisarze mają priorytet,
jeśli jakikolwiek pisarz chce pisać, żaden czytelnik
nie może zacząć czytać.
2. Nie ma priorytetu pomiędzy czytelnikami.
56/75
PRiR Wykład 3
SEMAFORY
int no_of_r,no_of_w = 0,0;
/*no_of_r - liczba procesów aktualnie czytających
no_of_w – liczba procesów, które chca pisać */
binary semaphore sp,sr = 1, 1;
binary semaphore w1, w2 , w3= 1, 1 ,1;
/*w1 – do dostępu do no_of_r
w2 – do dostępu do no_of_w
w3 – dodatkowa „śluza” dla czytelników
sp podobnie jak w poprzednim przykładzie
sr – dla priorytetu pisarzy */
57/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
19
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
process :: reader;
void main()
{
while(1)
{ BWait(w3);
BWait(sr);
BWait(w1);
no_of_r++;
if (no_of_r == 1) BWait(sp);
BSignal(w1);
BSignal(sr);
BSignal(w3);
/* czytanie */
BWait(w1);
no_of_r--;
if ( no_of_r == 0) BSignal(sp);
BSignal(w1);
};
};
process :: writer;
void main();
{
while(1)
{
BWait(w2);
no_of_w++;
if (no_of_w == 1 ) BWait(sr);
BSignal(w2);
BWait(sp);
/* pisanie */
BSignal(sp);
BWait(w2);
no_of_w--;
if (no_of_w==0) BSignal(sr);
BSignal(w2);
};
};
58/75
PRiR Wykład 3
SEMAFORY
Modyfikacje semaforów
Rozszerzone operacje na semaforach
Jednoczesne operacje na semaforach
(ang. Concurrent semaphore operations)
(Dijkstra)
DWait(s1,s2,...,si,...,sn);
Czekaj aż wszystkie si, si>0
for (i=1;i<=n;i++) si = si-1;
(i=1,...,n);
DSignal(s1,s2,...,si,...,sn);
for (i=1;i<=n;i++) si = si+1;
59/75
PRiR Wykład 3
SEMAFORY UOGÓLNIONE
Modyfikacje semaforów
Rozszerzone operacje na semaforach
Uogólnione operacje na semaforach
Wartość semafora jest zmieniana o wartość całkowitą n.
NWait(s ,n);
Czekaj aż s >= n;
s=s-n;
NSignal(s,n);
s = s+n;
60/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
20
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY UOGÓLNIONE
Modyfikacje semaforów
Rozszerzone operacje na semaforach
Uogólnione operacje na semaforach
•
•
Priorytety w dostępie do zasobów
Priorytety są realizowane na podstawie numeru
procesu.
Procesy z mniejszymi numerami mają wyższy
priorytet.
61/75
PRiR Wykład 3
SEMAFORY UOGÓLNIONE
semaphore prior = 2*N-1;
// N – number of processes
process:: Proc(name)
/*1 <=name<=N */
{
int i;
while(1)
{ NWait(prior,N+name-1);
/* prior == N-name żaden inny proces nie może wejść do sekcji krytycznej */
/*zażądaj zasobu; */
/*critical section */
/*zwolnienie zasobu */
NSignal(prior, name-1);
/* prior = =N-1
żaden proces nie może wejść do sekcji krytycznej */
for(i=1;i<=N;i++)
/* szukanie czekającego procesu z najwyższym priorytetem */
{
NSignal(prior,1);
/* prior == N+i-1
proces nr i wchodzi do sekcji krytycznej – przerywamy pętlę */
};
};
}
62/75
PRiR Wykład 3
SEMAFORY UOGÓLNIONE
Czytelnicy i pisarze bez priorytetu
semaphore w = M;
/* M > liczba czytelników */
process :: reader;
process :: writer;
{
{
while(1)
while(1)
{
{
NWait(w,1);
NWait(w,M);
/*M procesów może zmniejszyć w o 1*/
/*tylko jeden proces może
/* teraz czytanie */
zmniejszyć w do 0*/
NSignal(w,1);
/* teraz pisanie */
};
NSignal(w,M);
};
};
63/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
21
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY UOGÓLNIONE
Czytelnicy - pisarze z priorytetem dla pisarzy
int no_of_r, no_of_w = 0,0;
/*no_of_r – liczba aktualnie czytających procesów
no_of_w – liczba czekających pisarzy */
semaphore sp, r = M,M;
/* M>= liczby możliwych czytelników
sp podobnie jak we wcześniejszym przykładzie
r – dla realizowania priorytetu pisarzy */
64/75
PRiR Wykład 3
SEMAFORY UOGÓLNIONE
process :: reader;
void main()
{
while(1)
{
NWait(r,M);
NWait(sp,1);
NSignal(r,M-1);
/*pisarz może zwiększyć semafor r o 1 */
NSignal(r,1);
/*tu czytelnik czeka jeśli jakiś pisarz czeka */
/* czytanie */
NSignal(sp,1);
};
};
process :: writer;
void main()
{
while(1)
{
NWait(r,1);
NWait(sp,M);
/* pisanie */
NSignal(sp,M);
NSignal(r,1);
};
};
65/75
PRiR Wykład 3
SEMAFORY
n filozofów je rybę
66/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
22
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
n filozofów je rybę
Opis problemu:
N filozofów siedzi dokoła okrągłego stołu, każdy na
swoim miejscu. Jest n talerzy i n widelców na stole.
Talerze znajdują się na wprost filozofów, widelce leżą
pomiędzy talerzami.
Czynności filozofa:
Loop
Myśli
Chce podnieść swoje widelce
Je rybę posługując się widelcami
Odkłada widelce
67/75
PRiR Wykład 3
SEMAFORY
n filozofów je rybę.
Rozwiązanie problemu:
Spróbuj podnieść swoje widelce
Rozwiązanie 1.
Czekaj aż lewy widelec będzie wolny
Podnosi lewy widelec
Czekaj aż prawy widelec będzie wolny
Podnosi prawy widelec
Złe rozwiązanie : deadlock
68/75
PRiR Wykład 3
SEMAFORY
n filozofów je rybę.
Rozwiązanie problemu:
Spróbuj podnieść swoje widelce
Rozwiązanie 2:
Loop
{
Czekaj aż lewy jest wolny
Podnieś lewy
IF prawy jest zajęty
Odłóż lewy widelec
ELSE
{
Podnieś prawy widelec
EXIT
}
}
Złe rozwiązanie : busy waiting
69/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
23
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
n filozofów je rybę.
Rozwiązanie problemu:
Spróbuj podnieść swoje widelce
Wniosek:
Rozwiązanie 3:
•Czekaj, aż oba będą wolne
•Podnieś oba widelce w jednym ruchu
70/75
PRiR Wykład 3
SEMAFORY
n filozofów je rybę.
Rozwiązanie problemu:
Odłóż widelce
• Odłóż widelce – w dowolnej kolejności
• Obudź tego sąsiada, który czeka na widelec (jeśli
jego drugi widelec jest wolny) – czasami obu
71/75
PRiR Wykład 3
SEMAFORY
Pierwsze rozwiązanie z semaforami - deadlock
resource fork [N-1];
binary semaphore sem [N-1] = (N) 1;
process Philosopher (name);
{
while(1)
{
/* myśli */
/* chce jeść */
BWait ( sem[name] );
/* podnosi lewy widelec - fork[name] */
BWait ( sem[(name+1) % N] ) ;
/*podnosi prawy widelec - fork[(name+1) % N] */
/* jedzenie */
BSignal ( sem[name] );
/*odłożenie widelca fork[name] */
BSignal ( sem[(name+1) % N] ) ;
/* odłożenie widelca fork [(name+1) % N] */
};
};
72/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
24
Programowanie Równoległe i Rozproszone
Wykład 3
SEMAFORY
Prawidłowe rozwiązanie
state[i] = 0
i-ty filozof myśli
state[i] = 1
i-ty filozof chce jeść
state[i] = 2
i-ty filozof je
resource fork [N-1];
binary semaphore filsem [N-1] = 0;
/*każdy filozof ma swój własny semafor do czekania */
int state [N-1] = 0 ;
Boolean semaphore w = 1;
/* w do dostępu do tablicy stanów */
void test (k: integer);
{
if ((state [(k-1)% N] <> 2 ) and ( state[k]== 1) and ( state[(k+1)%N] <> 2 ))
{
state [k] = 2;
BSignal(filsem[k]);
};
};
73/75
PRiR Wykład 3
SEMAFORY
Prawidłowe rozwiązanie(cd.)
process Philosopher (name);
{
while(1)
{ /* mysli */
/* chce jeść */
BWait(w);
state[name] = 1;
test (name);
BSignal(w);
BWait ( filsem[name] );
/* filsem[name] może zostać opuszczony, TYLKO jeśli został podniesiony w
procedurze test(name) */
request (fork[name] , fork [(name+1) % N] ) ;
/* eating */
release (fork[name] , fork [(name+1) % N]) ;
BWait(w);
state[name] = 0;
test ((name-1) % N);
test ((name+1) % N);
/* sprawdzamy obydwu sąsiadów czy czekają */
/* odpowiednie semafory są podnoszone */
BSignal(w);
};};
74/75
PRiR Wykład 3
SEMAFORY
To samo z semaforami uogólnionymi:
semaphore sem [N] = 1;
void philosopher(int name);
{
while(1)
{
/* myśli */
DWait(sem[name], sem[(name+1) % N]);
/*je*/
DSignal(sem[name], sem[(name+1) % N]);
}
}
75/75
Przygotował: Lucjan Stapp
PRiR Wykład 3
25