Sunteți pe pagina 1din 19

9. Algoritmi und 9.1 Noiuni preliminare 9.1.1.

Sensul legturilor Complexitatea comunicrii ntr-un algoritm distribuit depinde de topologie, dar i de cunoaterea ei la nivelul fiecrui nod. n notaia folosit pn acum, instruciunile de comunicare de mesaje fceau appel la identificatori globali ai canalelor utilizate, care nu includeau nici un fel de informaie asupra topologiei globale a reelei de procese. O alternativ util n cazul topologiilor regulate este utilizarea unui singur set de etichete pentru oricare proces, care ar corespunde sensului legturilor cu procesele vecine sau direciilor ctre nodurile vecine. Dimensiunea setului depinde de topologie (de ex. 2 pentru inel, 4 pentru tor, etc). Se adaug o condiie suplimentar de consisten diferit de la o topologie la alta. Prezentm cteva exemple. Inel. Pentru fiecare nod din inel (Figura 9.1a) sunt 2 direcii, denumite: Prec (precedent) i Urm (urmtor). Condiia de consisten este: precedentul lui p este q urmtorul lui q este p

(a) Figura 9.1 Un inel (a) i o clic (b)

(b)

Clica. Clica (Figura 9.1b) conine N noduri de grad N-1. Setul direciilor este {1, 2, , N-1}, iar condiia de consisten este: direcia de la nodul i la j are eticheta (j-i) mod N Hipercub. Pentru un hipercub n dimensional (Figura 9.2), setul direciilor este {0,n-1}, iar condiia de consisten este:

120

doua noduri (b0,,bn-1), (c0,,cn-1) legate prin muchie cu eticheta i difera doar in bitul i

Figura 9.2 Hipercub Cu acestea, notaia pentru transmiterea unui mesaj poate avea dou forme: (1) transmitere prin adresare direct, folosit atunci cnd transmitorul cunoate identitatea unic, global a canalului q ctre receptor send ch[q] (mesaj) (2) transmitere prin adresare indirect, folosind etichete locale ale direciilor send ch[directie] (mesaj) unde directie identific unul din canalele pe care procesul poate transmite. 9.1.2. Sisteme de tranziii n capitolul 2 menionam c un program concurent este o colecie de procese paralele comunicante, iar execuia sa poate fi privit ca o ntreesere a aciunilor atomice ale proceselor. Programul concurent poate fi modelat printr-un sistem de tranziii, care pune n eviden strile coleciei de procese (numite convenional configuraii) i tranziiile ntre stri. Un sistem de tranziii const din muimea tuturor configuraiilor posibile ale sistemului, tranziiile pe care sistemul le poate face ntre configuraii i configuraiile din care sistemul poate porni.

121

Formal, un sistem de tranziii este un triplu S = (C, , I), unde C este o mulime de configuraii este relaia de tranziie binar pe C I este setul configuraiilor iniiale (o submulime a lui C) O execuie a lui S este o secven maximal E = (0, 1, 2, ), unde 0 aparine lui I i i i+1, pentru i>=0. O configuratie terminal nu are succesor (nu exist astfel nct ). O secven E este maximal dac este infinit sau sfrete ntr-o configuraie terminal. Configuraia este tangibil din dac exist o secvena 0, 1, 2, , k astfel nct = 0 = k i i+1, pentru i = 1, k-1. Prin convenie, se utilizeaz termeni diferii pentru elementele sistemului de tranziii si pentru procese. Astfel, o configuraie corespunde reuniunii strilor proceselor, iar o tranziie corespunde unui eveniment al unui proces. Evenimentele pot fi interne, sau de comunicare: send i receive. Cu aceasta, unei execuii E i corespunde o secven de evenimente din diferite procese. Pentru o execuie E, relaia de ordine cauzal < este cea mai slab relaie care satisface urmtoarele: dac a i b sunt dou evenimente diferite ale aceluiai proces i a se produce naintea lui b atunci a<b dac a este un eveniment send iar b evenimentul receive corespunztor atunci a<b dac a<c i b<c atunci a<c (< este tranzitiv). Dac nici a<b i nici b<a atunci a i b sunt concurente. Evenimentele unei execuii E pot fi re-aranjate n orice alt ordine consistent cu relaia de cauzalitate, fr a afecta rezultatul execuiei. Noua ordonare a evenimentelor produce o alt secven de configuraii, F despre care spunem c este echivalent cu prima. Mai precis, o execuie E este echivalent cu F (E~F) dac:

122

au aceeai colecie de evenimente (ordinea difer) evenimentele respect aceeai relaie de ordine cauzal ultima configuraie a lui E coincide cu ultima configuraie a lui F.

Obs. Dou execuii echivalente pot s nu aib aceleai configuraii. Folosind relaia "~" putem mpri execuiile unui sistem de tranziii n clase de echivalen. Vom numi calcul (computation), al unui algoritm distribuit, o clas de echivalen (sub relaia ~) a execuiilor algoritmului. Cu alte cuvinte, un calcul este o colecie de evenimente parial ordonat prin relaia de ordine cauzal. Numrul de evenimente dintr-un calcul C este notat |C|, iar submulimea evenimentelor produse n procesul p este notat Cp.

123

9.2. Algoritmi und (Wave algorithms) Muli algoritmi distribuii se bazeaz pe transmiterea de mesaje n conformitate cu o anumit schem, dependent de topologie, care asigur participarea tuturor proceselor. Ca exemple menionm algoritmii pentru: difuzarea informaiei, realizarea unei sincronizri globale ntre procese, declanarea unu eveniment n fiecare proces, calculul unei funcii n care fiecare proces particip cu o parte a datelor de intrare. Algoritmii und implementeaz astfel de scheme de transmitere de mesaje. Un algoritm und este un algoritm distribuit care are urmtoarele proprieti: terminare fiecare calcul este finit decizie fiecare calcul conine cel puin un eveniment de decizie (decide) dependena n fiecare calcul, fiecare decide este precedat cauzal de un eveniment din fiecare proces. Pentru un astfel de algoritm, un calcul (computation) este denumit und (wave). Se face distincie ntre dou categorii de procese: cele care iniiaz execuia, numite iniiatoare (starters) i celelalte procese, ne-iniiatoare (followers). Primul eveniment dintr-un proces iniiator este unul intern sau un send, n timp ce primul evniment dintr-un proces ne-iniiator este un receive. Algoritmii und pot fi clasificai dup mai multe criterii. Centralizarea. ntr-un algoritm centralizat exist un singur iniiator. ntr-un algoritm descentralizat exist un set arbitrar de iniiatori. Topologia. Poate fi inel, arbore, clic etc. Topologia este: fix atunci cnd nu se produc modificri topologice; conectat dac exist o cale ntre oricare dou procese. n general, topologia este nedirecionat (legturile ntre procese sunt bi-direcionale). Cunostinele iniiale ale unui proces pot include identitatea proprie (nume), identitile vecinilor, sensul direciei (ordinea vecinilor). Numrul de decizii. Regula general este "cel mult o decizie n fiecare proces." Putem avea una din urmtoarele situaii: un singur proces decide; toate procesele decid; doar unele decid. Complexitatetea unui algoritm distribuit se msoar n: numr de mesaje schimbate, numr de bii interschimbai sau n timpul necesar pentru un calcul. Pentru complexitatea in timp se aplica urmatoarele reguli:

124

- un proces poate executa orice numar finit de evenimente in timp nul; - timpul de la transmiterea la receptia unui mesaj este de cel mult o unitate de timp. Prezentm n continuare civa algoritmi und elementari. 9.2.1. Algoritmul inel Algoritmul are urmtoarele caracteristici: fiecare proces are un vecin dedicat, Urm transmiterea foloseste adresarea prin directie (Urm, Prec) toate canalele selectate prin Urm formeaza un ciclu Hamiltonian algoritmul este centralizat: initiatorul trimite un token (jeton) care este pasat de fiecare proces de-a lungul ciclului pana ajunge inapoi la initiator; initiatorul ia apoi decizia Descrierea este urmtoarea:
chan token[1..n] (tok: tok_type); /*initiator*/ P(I):: var tok: tok_type; send token[Urm](tok); receive token[I](tok); decide /*non-initiators*/ P(k:1..n, k<>I):: var tok: tok_type; receive token[k](tok); send token[Urm](tok);

Numr de mesaje = n Timp = n Obs. Regula folosit pentru calculul complexitii este urmtoarea: complexitatea n timp a unui algoritm distribuit este timpul maxim cerut de un calcul al algoritmului, in urmtoarele condiii un proces poate executa n timp zero orice numr finit de evenimente;

125

timpul ntre transmiterea unui mesaj i recepia lui este de (cel mult) o unitate de timp. 2.2. Algoritmul arbore Algoritmul se aplic unei topologii arbore. El poate fi aplicat i unei topologii arbitrare n care se cunoate un arbore de acoperire. Fiecare nod cunoate identitatea proprie i identitile vecinilor. Multimea tuturor identitatilor este Ids. Pentru fiecare proces, se folosesc variabilele locale: Vecini - mulimea identitilor vecinilor (notm q identitatea procesului q) rec[q] = true dac procesul a primit un mesaj de la vecinul q Iniiatorii sunt toate nodurile frunz. n algoritm: fiecare proces trimite exact un mesaj; cnd un proces a primit un mesaj pe fiecare canal incident mai puin unul (condiie ndeplinit iniial de frunze) el trimite un mesaj pe canalul rmas; cnd un proces a primit cte un mesaj pe toate canalele sale atunci decide.
chan ch[Ids] (id: Ids, tok: tok_type); /* fiecare proces are un canal propriu */ Proc(p:Ids):: var Vecini: set of Ids := vecinii_lui_p; rec: array [Ids] of bool := ([|Ids|]*false); var r: int := numar_vecini_p; tok:tok_type; id, q0: Ids; do r>1 -> receive ch[p](id,tok); rec[id] := true; r := r-1 od; /* de la un singur vecin, fie el q0, nu s-a primit mesaj */ q0 := id Vecini and rec[id]=false; send ch[q0](p, tok); x:receive ch[p](q0, tok); rec[q0] := true; decide; /* informeaza celelalte procese despre decizie */ /* fa q Vecini\{q0} -> send ch[q](p,tok) af; */

126

Numr de mesaje = N (fiecare proces trimite un mesaj) Timp = O(D) Un exemplu de execuie este prezentat n figura 9.3.

(a) nodurile frunza transmit

(b) nodurile de nivel intermediar transmit

(c) p si q transmit reciproc i, dup recepie, decid Figura 9.3 Exemplu de execuie al algoritmului arbore (Tel 1994) n continuare, justificm urmtoarea Teorem. Algoritmul "arbore" este un algoritm und. (justificarea ignor ultima instruciune fa din algoritm, cea inclus n ultimul comentariu). (1) calcul finit Fiecare proces trimite cel mult un mesaj => algoritmul folosete cel mult N mesaje => algoritmul atinge o configuraie terminal dup un numr finit de pai. n , cel puin un proces a executat un eveniment "decide" terminal => un exit nici un mesaj n tranzit;

(2)

127

pentru N noduri avem N-1 legturi bidirecionale ntre vecini => 2N-2 posibile recepii de mesaje (pentru care procesele ateapt n bucla dup "r" din algoritm). Fie K procese au trimis un mesaj n F recepii sunt neconsumate => F = 2N2K Presupunem prin absurd c nici un proces nu a executat "decide" n N-K procese nu au trimis mesaj => fiecare din ele mai are de primit cel puin 2 mesaje K procese au trimis dar nici unul nu a decis => fiecare mai are de primit un mesaj => F >= 2(N-K)+K Combinnd cele dou rezultate obinem: 2N2K >= 2(N-K)+K sau -2 >= 0, contradicie => cel puin un proces a executat "decide" n (3) "decide" este precedat de un eveniment in fiecare proces

Figura 9.4 Subseturile Tpq i Tqp (Tel 1994) Fie:

Tpq subsetul proceselor tangibile din p fr a parcurge legtura pq Tqp subsetul proceselor tangibile din q fr a parcurge legtura qp i evenimentele: fpq p trimite un mesaj lui q gpq q primete un mesaj de la p Se demonstreaz prin inducie peste evenimentele de recepie c: pentru orice s din Tpq exist e Cs : e gpq unde Cs este submulimea evenimentelor produse n procesul s iar denot relaia de preceden.

128

Figura 9.5 Descompunerea lui Tpq (Tel 1994)

Presupunem c aceasta este adevrat pentru toate evenimentele receive care preced gpq i demonstrm c este adevrat i pentru gpq. Observm c: gpq este precedat de fpq (n procesul p) (cf. algoritm p) fpq este precedat de grp de la fiecare vecin r care nu este q (cf. ipotez inducie) pentru toi r i pentru orice s din Trp, exist e din Cs cu e grp deci e gpq

Figura 9.5 Descompunera lui T (Tel 1994)

O decizie dp este precedat de grp pentru toi vecinii r => pentru orice Trp i orice proces s din Trp exist e n Cs: e grp dp => pentru orice proces s exista e n Cs: e dp

129

2.3. Algoritm ecou Algoritmul ecou are urmtoarele caracteristici: se aplic unor topologii arbitrare este centralizat - exista un singur initiator, I versiunea prezentat aici a fost propus de Segall (o variant anterioar, mai puin eficient aparine lui Chang) Ideea: algoritmul este bazat pe inundarea retelei cu mesaje tok pe parcursul acestei operaii se stabilete un arbore de acoperire peste topologia arbitrar de graf mesaje tok sunt transmise inapoi spre radacina prin canalele arborelui de acoperire.
chan ch[Ids] (id: Ids, tok: tok_type); const I=id_initiator; Proc(I):: var Vecini: set of Ids := vecinii_lui_I; var r: int := numar_vecini_I; tok:tok_type; id: Ids; fa q Vecini -> send ch[q](I, tok) af; do r>0 -> receive ch[I](id, tok); r := r-1 od; decide; Proc(p:Ids, p<>I):: var Vecini: set of Ids := vecinii_lui_p; var r: int := numar_vecini_p; tok:tok_type; id, parinte: Ids; receive ch[p](parinte, tok); r := r-1; fa q Vecini\{parinte} -> send ch[q](p, tok) af; do r>0 -> receive ch[I](id, tok); r := r-1 od; send ch[parinte](p, tok);

Numr mesaje = 2|E|, doua mesaje pe fiecare legatura bi-directionala. Timp = O(N) in fiecare etapa se adauga, in cel mai rau caz, un parinte.

130

2.4. Algoritmul fazelor Are urmtoarele proprieti: este un algoritm descentralizat se aplic unor topologii arbitrare n care sunt evideniate canale unidirectionale (digraf) vecinii sunt grupai n dou categorii: in-vecini i out-vecini procesele cunosc diametrul grafului D (sau o valoare D'>D) Ideea: fiecare proces trimite exact D mesaje fiecrui out-vecin. Functionarea proceselor este impartita in faze; in fiecare faza un proces p trimite un mesaj fiecarui out-vecin si primeste un mesaj de la fiecare in-vecin. Astfel, dupa doua faze, un proces primeste informatii propagate (prin intermediul in-vecinilor sai) de la procesele situate la distanta 2 fata de el. Dupa D faze, un proces primeste de la toate procesele situate la distanta mai mica sau egala cu D (altfel spus, de la procesele de la care exista o cale de distanta cel mult D pana la procesul curent). Dupa aceea procesul decide. In descrierea urmatoare, exista doua categorii de procese: Initiatori care pornesc cu trimiterea unui mesaj fiecarui out-vecin si Ne-initiatori care asteapta primirea unui prim mesaj si apoi trimit fiecarui out-vecin mesajele din prima faza a algoritmului.
chan ch[Ids] (id: Ids, tok: tok_type); const D = diametrul_retelei; Proc (p:Ids):: var in: set of Ids := in-vecinii_lui_p; var out: set of Ids := out-vecinii_lui_p; var rec: array [Ids] of int := ([|Ids|] 0); /* rec[q] = numar mesaje primite de la q */ var sent: int := 0; /* numar de mesaje transmise fiecarui out-vecin */ var tok:tok_type; id: Ids; if p este initiator -> fa q out -> send ch[q](p, tok) af; sent := sent+1; fi /* min(rec) este min(rec[q], Vq in) */

131

do min(rec) < D -> receive ch[p](id, tok); rec[id] := rec[id]+1; if min (rec) >= sent and sent < D -> fa q out -> send ch[q](p, tok) af; sent := sent+1; fi od; decide;

Numr mesaje = 2D|E|, unde E este multimea canalelor Timp = 2D Comentariu. Daca p este initiator, el transmite mesaje tuturor out-vecinilor si face sent=1. In bucla do, el asteapta apoi primirea unui set de mesaje de la in-vecini, pana cand primeste cel putin un mesaj de la fiecare in-vecin [min(rec)>=1]. Cand conditia este indeplinita, el transmite mesajele din urmatoarea faza. De fiecare data, trecerea la transmiterea mesajer din faza k+1 se face dupa primirea de la toti in-vecinii a mesajelor din faza k. Daca p nu este initiator, el intra direct in bucla do, unde asteapta primirea unui prim mesaj. Deoarece, pentru el, min(rec)=0 si sent=0, procesul trece la transmiterea mesajelor din prima faza, dupa care asteapta in bucla primirea mesajelor de la invecini. Comportamentul este apoi similar cu cel al proceselor initatoare. T. Algoritmul "fazelor" este un algoritm unda (1) calcul finit fiecare proces trimite cel mult D mesaje prin fiecare canal => algoritmul atinge o configuratie terminala dupa un numar finit de pasi in , fiecare proces a executat un eveniment "decide" o configuratie terminala a unui calcul C presupunem cel putin un initiator in C (pot fi mai multi) (2.1) fiecare proces a trimis cel putin un mesaj: - exista cel putin un initiator care transmite mesaje out-vecinilor sai - la randul sau, fiecare out-vecin trimite mesaje cel tarziu cand primeste un mesaj o configuratie terminala => nu exista mesaje in tranzit => pentru canal qp: recp[q] = sentq

(2)

132

p trimite mesaje cel tarziu cand primeste un mesaj => recp[q]>0 => sentp >0 exista cel putin un initiator p0 (sentp0 >0) => pentru fiecare out-vecin p, recp[p0] >0 => sentp >0 aplicand recursiv + retea conexa rezulta ca pentru orice p, sentp >0 (2.2) fiecare proces a decis Observatie. Un proces decide atunci cand iese din bucla do, deci atunci cand conditia min(rec)<D nu mai este indeplinita. Asta se intampla cand min(rec) devine egal cu D, adica procesul a primit mesaje de la toti in-vecinii in faza D. Cu alte cuvinte, nu exista vreun proces care sa fi trimis mai putin de D mesaje. Pentru demonstratie, luam in consideratie procesul cu cel mai mic numar de mesaje trimise. Fie p procesul cu cel mai mic sentp in => pentru orice proces q: sentq >= sentp in In particular, tine daca q este in-vecin al lui p adica minq (sentq) >= sentp pentru q in. Dar recp[q] = sentq (in , toate mesajele transmise au fost receptionate), deci minq (recp[q]) >= sentp Rezulta sentp =D; altfel p ar fi trimis mesaje suplimentare la ultima receptie (vezi decizia din algoritm). Ca urmare, => sentp =D pentru toti p => recp[q] =D pentru orice canal qp => fiecare proces a decis (3) "decide" este precedat de un eveniment in fiecare proces notatii: fpq(i) al i-lea eveniment "p transmite lui q" gpq(i) al i-lea eveniment "q primeste de la p" relatia "precede pe" canale FIFO => fpq(i) gpq(i) (dar se dem ca tine si pentru not FIFO) Fie P = p0, p1, , pk, cu k<=D o cale in retea. Sunt respectate urmatoarele proprietati: - transmiterea unui mesaj precede receptia lui, in aceeasi faza, la urmatorul proces din cale, adica fp(i)p(i+1)(i+1) g p(i)p(i+1) (i+1) pentru 0<=i<k

133

- receptia unui mesaj intr-o faza (i+1) precede transmiterea unmui mesaj in faza urmatoare (i+2), adica g p(i)p(i+1) (i+1) f p(i+1)p(i+2) (i+2) pentru 0<=i<k-1. Aplicand tranzitivitatea, rezulta fp(0)p(1)(1) g p(i-1)p(i) (k) Deoarece diametrul grafului este D, pentru oricare q si p exista o cale q= p0, p1, , pk = p de lungime cel mult D. Ca urmare, pentru orice q exista un k<=D si un in-vecin r al lui p a.i. fqp1(1) g rp (k). In plus, din algoritm avem ca g rp (k) dp.

134

2.5. Algoritmul fazelor pentru clici Proprieti: diametrul = 1 doar un mesaj trebuie primit de la fiecare vecin = se tine evidenta intr-o variabila simpla canale unidirectionale
chan ch[Ids] (id: Ids, tok: tok_type); Proc (p:1..N):: var Vecini: set of Ids := vecinii_lui_p; var n_vecini := numar_vecini_p; var rec: int := 0; var sent: int := 0; var tok:tok_type; id: Ids; if p este initiator -> fa q Vecini -> send ch[q](p, tok) af; sent := sent+1; fi do rec < n_vecini -> receive ch[p](id, tok); rec := rec+1; if sent = 0 -> fa q Vecini -> send ch[q](p, tok) af; sent := sent+1; fi od; decide;

Numr mesaje = N(N-1) Timp = 2

135

2.6. Algortimul lui Finn Algoritmul nu cere cunoasterea diametrului. El se bazeaza pe cunoasterea identificatorilor proceselor, folositi in mesajele care se transmit intre procese. Ideea: procesul p pastreaza doua multimi de ids: Inc multimea proceselor q pentru care un eveniment in q precede cel mai recent eveniment in p NInc multimea proceselor q pentru care fiecare vecin r are un eveniment care precede cel mai recent eveniment in p Algoritmul Proprietatile seturilor Inc si NInc se mentin astfel: - initial Inc = {p} NInc = - In algoritm, p trimite mesaje cu Inc si NInc de fiecare data cand unul din Inc sau NInc creste. Cand p primeste mesaje cu Inc si NInc, adauga noile procese la propriile Inc si Ninc (actualizeaza Inc si NInc prin operatii de reuniune). Cand p a primit un mesaj de la toti in-vecinii, p este inserat in Ninc. Inc si NInc includ treptat toate procesele. Un proces p decide dupa ce, in fiecare proces q, identificatorul acestuia a fost adaugat la Ninc.
type SOP = set of Ids; chan ch[1:N] (id: Ids, Inc:SOP, NInc: SOP); Proc (p:Ids):: var Inc:SOP := {p}; var NInc:SOP := ; var rec: array [Ids] of bool := ([|Ids|] false); /* de la cine a receptionat */ var out: SOP := out-vecinii_lui_p; var in: SOP := in-vecinii_lui_p; var rInc, rNInc:SOP; var id: int; if p este initiator -> fa q out -> send ch[q](p, Inc, NInc) af; fi

136

do Inc <> NInc -> receive ch[p](id, rInc, rNInc); Inc := Inc U rInc; NInc := NInc U rNInc; rec[id] := true; if Vid in: rec[id] -> NInc := NInc U {p}; if Inc sau NInc modificat -> fa q out -> send ch[q](p, Inc, NInc) af; fi od; decide;

Numr mesaje <= 4N|E| Timp = O(D)

T. Algoritmul lui Finn este un algoritm unda (1) calcul finit cele doua multimi Inc si NInc sunt crescatoare initial contin impreuna un id putand creste la 2N (N = numar procese) => numarul de mesaje transmise este limitat superior la 2N|E| => algoritmul atinge o configuratie terminala dupa un numar finit de pasi in , fiecare proces a executat un eveniment "decide" 2.1. in fiecare proces a trimis cel putin un mesaj pe fiecare canal (dem similara alg fazelor) daca p a trimis mesaje cel putin o data (fiecarui vecin) si q este vecin => q a trimis mesaje cel putin o data => fiecare proces a trimis cel putin un mesaj pe fiecare canal 2.2. in fiecare proces a decis 2.2.1. V p, Incp contine toate procesele (in ) daca exista pq atunci Incp este inclus in Incq (in ) dupa ultima modif, p trimite Incp iar q actualizeaza Incq graf tare conex => Incp = Incq pentru toti p si q V Incp contine p => Incp contine toate procesele in 2.2.2. V p si q, NIncp = NIncq fiecare proc a trimis un mesaj pe fiecare canal => fiecare proces a receptionat de la toti vecinii (Vid in: rec[id])=>

(2)

137

cf alg => p este adaugat la NIncp graf tare conex si orice NIncp contine p => NIncp contine toate procesele in => V p, Incp = NIncp => fiecare proces a decis in (3) "decide" este precedat de un eveniment in fiecare proces Fie evenimentul intern ap: NInc := NInc U {p}. Avem ap precede decidep. Pentru fiecare vecin r al lui p, un eveniment din r precede ap. Pentru s care nu este vecin, evenimentul as precede receptia unui mesaj receive ch[p](id, rInc, rNInc)cu s rNInc in care s rNInc (si acest eveniment precede decidep). Rezulta ca pentru orice p, un eveniment in fiecare proces precede decidep.

138

S-ar putea să vă placă și