Wykład czwarty: Struktury procesów
Transkrypt
Wykład czwarty: Struktury procesów
Occam Wykład czwarty Ten wykład dotyczy przykładowych struktur procesów jakie możemy konstruować w occamie. Wszystkie przykłady dotyczące tego zagadnienia pochodzą ze skryptu M.Wysockiego i B.Kwolka „Obliczenia równoległe i transputery w automatyce”. 1. Struktura producent – konsument Ta struktura została już zaprezentowana w poprzednim wykładzie. Jeden proces z grupy procesów pełni rolę producenta, a więc „wytwarza” dane, które są następnie „konsumowane” przez jeden lub większą ilość procesów konsumenckich. Taką strukturę można przedstawić przy pomocy odpowiedniego schematu: kan producent konsument Komunikacja z użytkownikiem (o ile jest konieczna) może się odbywać za pośrednictwem procesu producenta (wejście) i konsumenta (wyjście) lub tylko za pośrednictwem producenta. W tym ostatnim przypadku musi istnieć kanał zwrotny, którym producent otrzymywałby wyniki pracy konsumentów. Procesy komunikujące się z użytkownikiem muszą być umieszczone na transputerze zerowym. Zakładając, że kod procesu producenta został umieszczony w procedurze o nazwie producent, a kod procesu konsumenta w procedurze o nazwie konsument i że oba procesy komunikują się ze sobą przy pomocy kanału o protokole pozwalającym wysyłać tylko liczby typu INT, to kod programu opisujący taką strukturę można zapisać w occamie następująco: CHAN OF INT kan: PAR producent(kan) konsument(kan) 2. Struktura producent – konsument z procesem buforującym Ta struktura nie jest samodzielną strukturą, ale stanowi uzupełnienie struktury typu producent – konsument. Elementem dodanym do poprzedniej struktury jest proces buforujący. Jego zadaniem jest skrócenie czasu oczekiwania procesów na komunikację. Kod wykonywany przez taki proces może być zapisany następująco: PROC bufor (CHAN OF INT we,wy) WHILE TRUE INT buf: SEQ we?buf wy!buf : Poniżej przedstawiono kod programu, który tworzyłby taką strukturę procesów wraz ze schematem tej struktury: 1 Occam CHAN OF INT od, do: PAR producent od bufort do konsument producent(od) bufor(od,do) konsument(kan) To rozwiązanie pozwala producentowi „wytworzyć” i wysłać daną bez konieczności oczekiwania na gotowość do odbioru procesu konsumenta. Można wprowadzić modyfikację tego układu dodając do procesu bufora osobny kanał, którym proces konsumencki mógłby sygnalizować buforowi gotowość do odebrania danej: PROC bufor.daj (CHAN OF INT we, daj, wy) INT buf: To rozwiązanie również nie jest pozbawione wad. Możliwe jest, że proces konsumencki będzie odbierał kilkukrotnie tę samą daną lub nie odbierze którejś z danych, które są wysyłane przez producenta. Lepszym rozwiązanie byłoby zastosowanie tablicy 1 buforów . Wartość indeksu wskazującego kolejne miejsce w tej tablicy (bufor), które może być wypełnione lub kolejne miejsce, które może być opróżnione musiałaby być przekazywana przez kanał. Ten schemat wymagałby uważnego rozważenia kwestii 2 modyfikacji wartości indeksu . Przedstawione tu procesy buforujące działają ciągle za sprawą niekończącej się pętli WHILE. W rzeczywistości należy określić jakiś warunek jej zakończenia. Może to być np.: otrzymanie przez kanał o protokole z wariantami odpowiedniej etykiety. SEQ we?buf INT x: WHILE TRUE ALT we?buf SKIP daj?x wy!buf : Opisaną wyżej strukturę można rozszerzyć na większą niż trzy grupę procesów. 3. Struktura multiplekser – demultiplekser Multiplekser jest procesem iteracyjnym, który odbiera informacje wieloma kanałami i wysyła je do jednego kanału. Działanie demultipleksera jest odwrotne – odbiera informacje jednym kanałem i wysyła je do jednym z kilku kanałów wyjściowych. Procesami współpracującymi z multiplekserem są producenci, natomiast procesami współpracującymi z demultiplekserem są konsumenci. Oto schemat takiej struktury: prod 1 prod 2 od[0] do[0] od[1] kan mux kan demux kon 1 do[1] kon 2 . . . . . od[n-1] do[n-1] . prod n kon n 1 W tym wypadku byłaby to oczywicie tablica elementów typu INT. 2 Ten temat jest poruszony midzy innymi w ksice A.Silberschatza, J.L.Petersona, P.B.Galvina „Podstawy systemów operacyjnych”, WNT, Warszawa 1993 2 Occam Multiplekser odbiera dane z jednego z kanałów wejściowych i wysyła je do procesu demultipleksera, wraz z informacją, do którego konsumenta należy tą daną wysłać. Demultiplekser odbiera tę informację i przekazuje ją do wskazanego procesu. Taka konstrukcja wymaga zdefiniowania odpowiednich protokołów kanałów. Protokół kanałów od i do będzie zdefiniowany następująco: PROTOCOL kom CASE dana;INT koniec : Protokół kanału kan będzie natomiast zdefiniowany następująco: PROTOCOL kom.ident CASE dana;INT;INT koniec : Załóżmy, że procesy konsumenta i producenta są opisane procedurami, które mają następujące nagłówki: PROC prod(CHAN OF kom wy) PROC kons(CHAN OF kom we) a procesy multipleksera i demultipleksera opisane procedurami o następujących nagłówkach: PROC mux([n] CHAN OF kom we, CHAN OF kom.ident wy) PROC demux(CHAN OF kom.ident we, [n] CHAN OF kom wy) Wówczas program tworzący taką strukturę mógłby mieć następującą postać: CHAN OF kom.ident kan: PAR [n] CHAN OF kom od: PAR i=0 FOR n prod(od[i]) mux(od,kan) [n] CHAN OF kom do: PAR demux(kan,do) PAR i=0 FOR n kons(do[i]) 3 Occam Procesy multipleksera i demultipleksera mogłyby wykonywać następujący kod: PROC mux([n] CHAN OF kom we, CHAN OF kom.ident wy) PROC demux(CHAN OF kom.ident we, [n]CHAN OF kom wy) INT liczba.nzak: BOOL praca: [n] BOOL nzak: SEQ BOOL praca: praca:=TRUE SEQ WHILE praca liczba.nzak:=n INT numer, wart: SEQ i=0 FOR n we?CASE nzak[i]:=TRUE koniec praca:=0<liczba.nzak praca:=FALSE WHILE praca dana;numer;wart ALT i=0 FOR n SEQ INT wart: IF nzak[i]&we[i]?CASE (0<=numer) AND (numer<n) koniec wy[numer]!dana;wart SEQ TRUE liczba.nzak:=liczba.nzak-1 SKIP nzak[i]:=FALSE PAR i=0 FOR n praca:=0<liczba.nzak dana;wart wy[i]!koniec : wy!dana;i;wart wy!koniec : Zmienna „liczba.nzak” oznacza liczbę nie zakończonych jeszcze procesów producenta, natomiast tablica „nzak” informuje o stanie każdego z nich. 4. Struktura typu farmer – worker Ta struktura składa się z procesu nadrzędnego określonego mianem „farmera”, który rozdziela zadania między procesy mu podporządkowane, nazywane „worker'ami”. Procesy te wyniki swego działania przekazują do procesu nadrzędnego, który może im przekazać inne zadania. Taka struktura może być przedstawiona za pomocą następującego schematu: 4 Occam farmer dla[0] od[0] dla[1] od[1] dla[n-1] worker worker 1 2 od[n-1] worker . . . n Przekazanie zadań odbywa się zgodnie z protokołem o nazwie Zadania: PROTOCOL Zadania CASE nowe.zad;INT;REAL64 koniec : Wyniki są przekazywane zgodnie z protokołem o nazwie Wyniki: PROTOCOL Wyniki IS INT; REAL64: Program tworzący przedstawioną na schemacie strukturę mógłby mieć następującą postać: [n] CHAN OF Zadania dla: [n] CHAN OF Wyniki od: [liczba.zad] REAL64 zad: [liczba.wyn] REAL64 wyn: ... PAR farmer(zad,dla,od,wyn) PAR j=0 FOR n Procesy farmera i workera następującymi procedurami: worker(dla[j],od[j]) 5 mogłyby być opisane Occam PROC worker(CHAN OF Zadania od.farm, CHAN OF Wyniki do.farm) BOOL tak: SEQ tak:=TRUE WHILE od.farm?CASE INT i: REAL64 zad, wyn: nowe.zad;i;zad SEQ wyn:=f(zad) do.farm!i;wyn koniec tak:=FALSE : PROC farmer(VAL []REAL64 zad, [n] CHAN OF Zadania do.work, [n] CHAN OF Wyniki od.work, [n] REAL64 wyn) SEQ PAR j=0 FOR n do.work[j]!nowe.zad;j;zad[j] SEQ i=n FOR (SIZE zad) – n ALT j=0 FOR n INT k: od.work[j]?k;wyn[k] do.work[j]!nowe.zad;i;zad[i] SEQ i=0 FOR n ALT j=0 FOR n INT k: od.work[j]?k;wyn[k] do.work[j]!koniec : 6