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