Pobierz prezentację
Pobieranie prezentacji. Proszę czekać
OpublikowałWioletta Poczta Został zmieniony 11 lat temu
1
4. TEORETYCZNE MODELE PROCESÓW WSPÓŁBIEŻNYCH Teoretyczne modele uwzględniają wybrane cechy rzeczywistych procesów, stanowiąc kompromis pomiędzy łatwością i jakością modelowania. Konstruując model obliczeń należy mieć na względzie: 1) czy korzystamy z pamięci dzielonej, czy z przesyłania komunikatów (raczej nie miesza sie tych dwóch rzeczy); 2) jakie akcje uznajemy za elementarne, to jest wykonywane niepodzielnie - niezależnie od akcji innych procesów. Przykład (Z. Manna, A. Pnueli) Obliczyć wartość dwumianu Newtona dla n, k naturalnych, n k. n! n · (n - 1) ·... · (n - k + 1) ( k czynników ) k! (n - k)! 1 2 ·... · k ( k czynników ) Wartość tego wyrażenia jest zawsze liczbą naturalną dla n, k takich, że n k.
2
Sposób obliczenia: współbieżnie wykonujemy mnożenia w liczniku i mianowniku, i na bieżąco wykonujemy dzielenia - wtedy, kiedy tylko jest to możliwe (ten sposób jest dobry, gdyż możemy uniknąć przekroczenia zakresu arytmetyki komputera, pomimo że licznik i mianownik oddzielnie mogłyby ten zakres przekroczyć). n, k - dane l, m - zmienne pomocnicze, przyjmujące odpowiednio wartości l : n, n-1,..., n - k + 1 m: 1,2,..., k b - wartość ułamka (na początku b = 1) Proces P 1 mnoży b przez kolejne wartości l, proces P 2 dzieli b przez kolejne wartości m, ale dopiero wtedy, kiedy jest to wykonalne: w żadnej chwili liczba wykonanych dzieleń nie może przekroczyć liczby wykonanych mnożeń, czyli musi zachodzić m n - l, aby można było wykonać dzielenie, zatem warunkiem wykonania dzielenia jest l + m n.
3
{ n, k : dane } l : n ; m : 1 ; b : 1 ; while l n - k do while m k do begin begin P 1 : b : b l ; || P 2 : await ( l + m ) n ; l : l - 1 b : b div m ; end ; m : m + 1 end; { b : wynik } Założenia: 1) zmienne n, k, b umieszczone są w pamięci wspólnej i oba procesy używają dla nich takich samych nazw; 2) sprawdzenia warunków oraz instrukcje podstawienia wykonywane są niepodzielnie.
4
Instrukcja await (wb), gdzie wb jest wyrażeniem boolowskim, zawiesza wykonywanie procesu do momentu, gdy zacznie zachodzić wb = true. Gdyby działanie await (wb) było interpretowane jako: wb ? T F byłoby to tak zwane aktywne czekanie (ciągłe sprawdzanie wartości wb absorbuje moc oblicze- niową procesora). W praktyce częściej następuje zawieszenie wykonywania procesu przez system operacyjny tak, aby nie marnować mocy procesora, więc bardziej adekwatnym schematem byłby schemat: wb ? T F
5
Działanie programów sekwencyjnych często przedstawiane jest za pomocą schematów blokowych. Dla programów współbieżnych dogodniejszą formą ilustracji ich działania są diagramy przejść. stan przejście c ? instr warunek logiczny instrukcja (strażnik przejścia) wykonywana niepodzielnie Jeżeli dla każdego stanu zachodzi, że wszystkie przejścia wychodzące z tego stanu mają warunki parami wykluczające się, program nazywamy procesowo deterministycznym. Omawiany przykład jest procesowo deterministyczny. s
6
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 5 m = 1 b = 1 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
7
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 5 m = 1 b = 1 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
8
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 5 m = 1 b = 1 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
9
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 5 m = 1 b = 5 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
10
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 4 m = 1 b = 5 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
11
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 4 m = 1 b = 5 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
12
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 4 m = 1 b = 5 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
13
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 4 m = 1 b = 20 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
14
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 4 m = 1 b = 20 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
15
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 4 m = 2 b = 20 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
16
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 4 m = 2 b = 20 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
17
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 3 m = 2 b = 20 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
18
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 3 m = 2 b = 20 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
19
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 3 m = 2 b = 20 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
20
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 3 m = 2 b = 10 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
21
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 3 m = 2 b = 30 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
22
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 2 m = 2 b = 30 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
23
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 2 m = 3 b = 30 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
24
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 2 m = 3 b = 30 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
25
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 2 m = 3 b = 30 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
26
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 2 m = 3 b = 10 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
27
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 2 m = 3 b = 10 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
28
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 2 m = 4 b = 10 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
29
l n - k ? m k ? m: m +1l: l -1 n = 5 k = 3 l = 2 m = 4 b = 10 p0p0 p1p1 p2p2 p3p3 r0r0 r1r1 r2r2 r3r3 r4r4 b: b l m k ? l + m n ? b : b div m
30
W powyższym diagramie pojedyncze strzałki odpowiadają pojedynczym operacjom niepodziel- nym. Wielkość jednostek syntaktycznych programu, o których możemy założyć, że będą wyko- nane niepodzielnie, nazywamy ziarnistością (granularity). Przedstawiony program charakteryzuje się niedeterminizmem wykonania, gdyż jego wykonanie może być modelowane przez różne przeploty operacji niepodzielnych obu procesów, np. P 1 P 1 P 2 P 1 P 2 P 1........... lub P 1 P 1 P 1 P 2 P 1 P 2........... Natomiast pomimo to stan końcowy programu (wektor wartości zmiennych i wskaźników instrukcji) jest w każdym przypadku taki sam, niezależnie od wykonanego przeplotu - taki program nazywamy zdeterminowanym (wszystkie współbieżne programy transformacyjne powinny posiadać tę cechę).
31
W przypadku korzystania ze wspólnej pamięci efekt wykonania programu współbieżnego może zależeć od ziarnistości. Przykład {y = 1 - wartość początkowa} P 1 : y = y + 1 P 2 : y = y - 1 Jeżeli założymy, że instrukcje podstawienia wykonywane są niepodzielnie, to zarówno dla prze- plotu P 1 P 2, jak i P 2 P 1 wynikiem wykonania będzie y = 1. W praktyce kompilator może przełożyć te instrukcje na następujące ciągi rozkazów maszynowych: LOAD Rejestr1, y LOAD Rejestr2, y P 1 : ADD Rejestr1, #1 P 2 : SUB Rejestr2, #1 STORE Rejestr1, y STORE Rejestr2, y (Zakładamy, że każdy proces używa swojego lokaknego rejestru).
32
Zakładając, że wszystkie przeploty rozkazów z przekładów P 1 i P 2 są dopuszczalne, otrzymujemy trzy różne wyniki dla różnych przeplotów: P 1 P 1 P 1 P 2 P 2 P 2 y = 1 Liczba wszystkich przeplotów ciągu P 1 P 1 P 2 P 1 P 2 P 2 y = 0 m - elementowego z ciągiem n - elementowym P 1 P 2 P 1 P 2 P 2 P 1 y = 2 (m + n) ! m ! n ! (inne przeploty dałyby jeden z tych trzech wyników). Zmniejszenie ziarnistości spowodowało zatem, że program przestał być zdeterminowany. W języku inżynierskim zjawisko, kiedy wynik zależy od przypadkowych czasów wykonania (lub, dla układów scalonych, od przypadkowych różnic w czasach propagacji sygnałów elektrycznych) nazywane jest hazardem. Nie należy projektować niczego, czego efekt wykonania mógłby zależeć od hazardu ! wynosi
33
Powyższy przykład był prosty, bo wszystkie występujące w nim rozkazy maszynowe co najwyżej raz wykonywały cykl pamięciowy. Jego analiza odnosi się więc zarówno do wykonania z przeplo- tem (drobnoziarnistym) na pojedynczym procesorze, jak i do wykonania równoległego na dwóch procesorach mających dostęp do wspólnej pamięci. Różnica mogłaby wystąpić w przypadku, gdyby dwa procesory równolegle wykonywały rozkazy wymagające dwóch odwołań do pamięci - np. rozkaz dodania zawartości akumulatora do zawartości komórki pamięci z pozostawieniem wyniku w pamięci. W takim przypadku do modelowania należałoby stosować jeszcze drobniejszą ziarnistość - na poziomie mikrorozkazów (operacjami niepodzielnymi są odczyt / zapis z /do pamięci i wykonanie operacji na samych rejestrach).
34
5. NISKOPOZIOMOWE MECHANIZMY ZAPEWNIANIA NIEPODZIELNOŚCI OPERACJI Możliwość zapewnienia niepodzielności operacji (będących ciągami operacji elementarnych) na komórkach pamięci wspólnej jest w programowaniu współbieżnym sprawą o zasadniczym zna- czeniu. Szczególnie w przypadku rzeczywistej równoległości widoczna jest potrzeba zabezpiecze- nia pojedynczym procesom prawa wyłączności dostępu (na pewien czas) do zmiennych dzielonych, ale w przypadku drobnoziarnistego przeplotu też to jest istotne. Ciąg instrukcji programu operujących na współdzielonych zasobach (pamięci dzielonej, wspólnych plikach itp.), który powinien być wyko- nany niepodzielnie, nazywamy sekcją krytyczną programu. Jakie są sposoby zabezpieczania sekcji krytycznych ? Jeżeli współbieżność jest symulowana na pojedynczym procesorze przez system operacyjny i sekcje krytyczne nie są związane z pamięcią wspólną, ale innymi zasobami (pliki, kolejki), proste operacje na tych zasobach są dostępne w postaci wywołań funkcji systemowych. Funkcje systemowe są wykonywane przez jądro systemu na zamówienie procesu i niepodzielność ich wykonania jest zapewniana przez system operacyjny.
35
Jeżeli mają być wykonywane operacje na pamięci wspólnej, lub bardziej złożone operacje na dowolnych zasobach, programista musi sam zadbać o ich zabezpieczenie. Najprostszym mecha- nizmem abstrakcyjnym służącym do tego celu są semafory. Podstawowym rodzajem semafora jest semafor binarny, będący obiektem, którego jedyne pole może przyjmować tylko wartości 0 i 1, a jedyne operacje, jakie można na nim wykonać, to: P (czekaj) V (sygnalizuj) Definicje tych operacji jest następująca: P(S) - jeżeli S>0, to zmniejsz S o 1, w przeciwnym razie wstrzymaj wykonywanie procesu; V(S) - jeżeli są jakieś procesy wstrzymane przez semafor S, to wznów jeden z nich, w przeciwnym razie jeśli S=0, to zwiększ S o 1.
36
Uwaga. 1) Skutek próby otwarcia otwartego semafora binarnego zależy od implementacji. Dojście do takiej sytuacji świadczy o błędzie w programie (i system operacyjny zazwyczaj reaguje sygnalizacją błędu). 2) Same operacje na semaforach muszą być wykonywane niepodzielnie. W systemach z przeplo- tem realizowane są jako funkcje systemowe, natomiast w sytuacji rzeczywistej równoległości ich implementacja musi być wspierana przez odpowiedni sprzęt (procesory z niepodzielnymi rozkazami typu test-and-set). 3) Niedeterminizm uruchamiania procesów czekających pod semaforem może podlegać różnym ograniczeniom (pojęcia związane z szeregowaniem wykonywania procesów będą omówione na następnym wykładzie).
37
Przykład Użycie semafora binarnego do zabezpieczenia sekcji krytycznej w przypadku dwóch procesów. {na początku S=1} while true do while true do begin begin niekrytyczna1; niekrytyczna2; P 1 : czekaj(S); || P 2 : czekaj(S); krytyczna1; krytyczna2; sygnalizuj(S) sygnalizuj(S) end end Uwaga. Przyjmujemy założenie, że każde wykonanie zarówno sekcji krytycznej, jak i niekrytycznej zajmuje skończony czas (procesy nie zapętlają się w nich ani nie zawieszają).
38
{ S = 1 } niekrytyczna1 krytyczna1 S > 0 ? S = 0 S := S+1 niekrytyczna2 S > 0 ? S = 0 krytyczna2 S = S+1 Uwaga. Gdyby w powyższym przykładzie zrównoleglić trzy takie procesy lub więcej, wzajemne wykluczanie byłoby dalej zapewnione, ale jeden z procesów mógłby zostać zagłodzony.
39
Uogólnienia semafora binarnego: 1) semafor ogólny - różni się od binarnego tym, że może przyjmować dowolne wartości naturalne, zaś operacja V, jeżeli nie czeka żaden proces, zwiększa zawsze wartość S o 1; 2) semafor ograniczony - może przyjmować wartości naturalne z zakresu od 0 do pewnego n. Zawieszenie procesu powoduje zarówno próba zmniejszenia wartości semafora poniżej 0, jak i próba zwiększenia powyżej n ; 3) semafor wielokrotny - pozwala na wykonywanie niepodzielnych operacji na wielu wartościach jednocześnie (będzie omówiony przy okazji opisu implementacji w systemie Linux). Uwaga. W językach programowania dysponujących standardowymi zestawami instrukcji wszystkie rodzaje semaforów są wzajemnie zastępowalne. Do rozwiązania konkretnych problemów jedne rodzaje mogą jednak być wygodniejsze, niż inne.
40
Przykład Jeżeli w sieci lokalnej jest 5 ogólnodostępnych drukarek, to dostęp wielu procesów do nich można skoordynować przy użyciu semafora przyjmującego wartości 0... 5. Przykład Problem producenta i konsumenta z n - miejscowym buforem cyklicznym. while true do while true do begin begin produkuj(e); czekaj(elementy); czekaj(miejsca); e := bufor(wy); P 1 : bufor(we) := e; P 2 : wy := (wy + 1) mod n; we := (we + 1) mod n; sygnalizuj(miejsca); sygnalizuj(elementy) konsumuj(e) end end producentkonsumentbufor
41
W przypadku komunikacji przez kanał przyjmujemy, że dostępne są niepodzielnie wykonywane funkcje send(, expr) i receive(, e), gdzie e jest zmienną, expr jest wyrażeniem tego samego typu, co e, a jest kanałem mogącym pomieścić ciąg elementów tego samego typu, co e. Kanał może mieć pojemność skończoną (w szczególnym przypadku 0) lub nieskończoną. Funkcja send zawiesza wyko- nywanie procesu, jeśli kanał jest pełny, funkcja receive zawiesza proces przy próbie pobrania z kanału pustego. Przykład Rozwiązanie problemu producenta i konsumenta przy użyciu kanału. while true do while true do begin begin P 1 : produkuj(e); P 2 : receive(, e); send(, e) konsumuj(e) end end
42
Monitory są deklarowalnymi obiektami mającymi zagwarantowaną niepodzielność wykonywania ich metod. Jest zatem niemożliwe współbieżne wykonanie operacji w jednym monitorze, ale możliwe w kilku różnych monitorach. Monitory są bardzo naturalnym mechanizmem ochrony sekcji krytycz- nych.
Podobne prezentacje
© 2024 SlidePlayer.pl Inc.
All rights reserved.