Documente Academic
Documente Profesional
Documente Cultură
Stabilirea topologiei
Initiator::
var i: int := indexul nodului initiator;
var top: array[1:N,1:N] of bool;
var T : tip_arb, m : tip_mesaj;
calculeaza T pe baza top;
m := mesaj_de_transmis;
send sondaj[i](T,m);
În cazul în care nodul iniţiator nu cunoaşte topologia, iar fiecare nod cunoaşte doar
vecinii, difuzarea mesajului se poate face dacă fiecare nod retransmite mesajul primit
88
tuturor vecinilor săi, ignorând copiile acestuia. Pentru a furniza o soluţie complet
simetrică, adoptăm convenţia că primul mesaj care se difuzează este retransmis chiar
şi nodului de la care provine. În acest mod, fiecare nod cunoaşte precis numărul
nodurilor de la care primeşte sau cărora le transmite mesajul. Soluţia are descrierea
următoare:
chan sondaj[1:n](tip_mesaj);
Nod(p:1..n)::
var leg: array [1:n] of bool := vecinii_lui_p;
var num: int := numarul_vecinilor;
var m: tip_mesaj;
receive sondaj[p](m);
fa q := 1 to n st leg[q] -> send sondaj[q](m); af;
fa q := 1 to num-1 -> receive sondaj[p](m); af;
Initiator::
var i:int := indexul_nodului_initiator;
var m: tip_mesaj;
m := mesaj_de_transmis;
send sondaj[i](m);
Ca un alt exemplu, vom considera problema stabilirii topologiei unei reţele. Fiecare
nod al reţelei este reprezentat de un proces, iar legăturile dintre noduri sunt realizate
prin canale. Fiecare nod poate comunica doar cu vecinii săi, cu care are canale directe
de legătura. Iniţial, fiecare nod cunoaşte aceste canale şi, implicit, vecinii. Problema
este ca fiecare nod să determine topologia întregii reţele. Aceasta informaţie ar putea
fi folosită în dirijarea mesajelor între noduri neadiacente. Vom reprezenta fiecare nod
printr-un proces Nod(p:1..N). Un tablou de legături, leg[1:N], local fiecarui proces,
va preciza vecinii nodului p:
pentru p, leg[q]=TRUE daca q este vecin cu p, altfel leg[q]=FALSE.
89
Relaţia de vecinătate este simetrică, astfel că
pentru p, leg[q]=TRUE <=> pentru q, leg[p]=TRUE.
Topologia care trebuie calculată este reprezentată în fiecare nod prin matricea de
adiacenţă top, având elementele :
top[i,j]=TRUE , dacă i este vecin cu j
top[i,j]=FALSE , în caz contrar.
Evident, top se calculează folosind valorile cunoscute leg ale fiecărui proces p, astfel
că, la terminarea calcului, următorul predicat este satisfacut:
Problema are o rezolvare foarte simplă în cazul variabilelor partajate: este suficient
ca fiecare proces p sa actualizeze linia p a matricei top. Deoarece procesele folosesc
elemente de matrice din linii diferite, non-interferenţa este asigurată.
O altă soluţie simplă este cea centralizată: fiecare proces trimite informaţii despre
vecinii săi unui proces central care alcătuieşte matricea de adiacenţă, pe care o
retransmite apoi diferitelor noduri. Deoarece nu toate nodurile sunt vecine cu nodul
central, rezolvarea este inevitabil asimetrică, unele noduri jucând şi rolul de
intermediere a transferului de mesaje, în timp ce altele nu (prezentăm această soluţie
ceva mai târziu).
O soluţie uniformă este cea distribuită: fiecare proces calculează singur topologia,
folosind informaţiile provenite de la vecini. Dacă fiecare nod transmite vecinilor
informaţia din matricea sa de adiacenţă şi, în acelaşi timp, primeşte matricea de
adiacenţă a fiecărui vecin, după un rund complet, fiecare nod va dispune de informaţii
despre noduri aflate la distanţa 2 de el. După două runde complete, orice nod va avea
informaţii despre noduri aflate la distanţa 3, etc. În general, dupa r runde sunt
completate liniile din top corespunzătoare nodurilor q aflate la o distanţă d <= r, adică
următorul predicat este satisfăcut pentru fiecare proces p:
RUND: ( oricare ar fi q cu 1<=q<=N: dist(p,q) <=r => top[q,*] este completat )
unde dist(p,q) este distanţa de la p la q, adică lungimea căii celei mai scurte între cele
două noduri.
90
Cunoscând diametrul D al unei reţele, putem face calculul topologiei după următorul
algoritm:
Algoritmul are două neajunsuri: unul este faptul că, în general, D nu este cunoscut;
cel de al doilea este traficul inutil, anumite noduri primind mesaje chiar după
actualizarea completă a tabloului top local.
Pentru a ocoli aceste neajunsuri, trebuie să observăm că, deoarece reţeaua este
conexă, putem considera că un nod cunoaşte întreaga topologie dacă fiecare linie top
are cel puţin un element TRUE. În acest moment, procesul p trebuie să mai execute
un singur rund, după care se poate termina. Acest ultim rund este necesar pentru a
transmite vecinilor informaţiile recente primite, eventual, la rundul precedent.
Totodată, procesul poate culege ultimele mesaje care îi sunt transmise, evitând
abandonarea mesajelor în canale. Deoarece un nod poate termina cu un rund înainte
sau după vecinii săi, sunt necesare măsuri suplimentare de evitare a blocării
91
definitive: un proces transmite mesaje doar vecinilor care nu s-au terminat şi preia
doar mesajele pe care aceştia le trimit.
Stabilirea topologiei unei reţele are şi alte soluţii. Unele se bazează pe mesajele de
sondaj cu ecou, la care ne referim în cele ce urmează. Ea foloseşte mesajele de sondaj
pentru a difuza informaţia într-o reţea.
Pentru început, să presupunem că reţeaua este un graf aciclic, mai precis un arbore şi
că nodul iniţiator i este rădăcina acestuia. Nodul i trimite un mesaj de sondaj tuturor
vecinilor (fiilor). Ca urmare, mesajele se propagă spre frunze. Deoarece acestea nu au
alţi vecini, ele încep faza de transmitere a ecourilor. Fiecare frunză trimite un mesaj
cu topologia vecinilor săi, către părinte.
const sursa=i;
type tip_leg = array [1:n] of bool;
tip_top = array [1:n, 1:n] of bool;
chan sondaj[1:n](transm: int);
chan ecou[1:n](top: tip_top);
chan ecou_final(top: tip_top);
93
Nod(p:1..n)::
var leg: tip_leg := vecnii_lui_p;
var top: tip_top := ([n*n] false);
top[p, 1..n] := leg;
var top_nou: tip_top;
var parinte: int;
receive sondaj[p](parinte);
{transmite sondaje celorlalte noduri vecine, copiii lui p}
fa q := 1 to n st leg[q] and (q<>parinte) ->
send sondaj[q](p);
af;
{primeste ecourile si fa reuniunea lor}
fa q := 1 to n st leg[q] and (q<> parinte) ->
receive ecou[p](top_nou);
top := top or top_nou;
af;
if p=sursa -> send ecou_final(top);
[] p<>sursa -> send ecou[parinte](top);
fi;
Initiator::
var top: tip_top;
send sondaj[sursa](sursa);
receive ecou_final (top);
Nod(p:1..n)::
var leg: tip_leg := vecinii_lui_p;
var top: tip_top := ([n*n] false);
top[p, 1:n] := leg;
94
var top_nou: tip_top;
var prim: int; {nodul de la care s-a primit prima sonda}
var k:fel, transm:int;
var nr_ecouri: int := numar_vecini - 1;
receive sonda-ecou[p](k, prim, top_nou);
{transmite sondaje celorlalte noduri vecine, copiii lui p}
fa q := 1 to n st leg[q] and (q<>prim) ->
send sonda-ecou[q](sonda, p, O); {topologie nula}
af;
{primeste ecourile si fa reuniunea lor, sau sonde si ignora}
do nr_ecouri>0 ->
receive sonda-ecou[p](k, transm, top_nou);
if k=sonda -> send sonda-ecou[transm](ecou, p, O);
[] k=ecou ->
top := top or top_nou;
nr_ecouri := nr_ecouri-1;
fi
od;
if p=sursa -> send ecou_final(top);
[] p<>sursa -> send sonda-ecou[prim](ecou, p, top);
fi;
Initiator::
var top: tip_top;
send sonda-ecou[sursa](sonda, sursa, O);
receive ecou_final (top);
95
Exerciţii
2) Imperechere distribuită. Sunt date n procese, fiecare corespunzând unui nod dintr-
un graf. Fiecare nod poate comunica doar cu vecinii săi. Fiecare proces încearcă să se
împerecheze cu un vecin. La terminarea împerecherii, fiecare proces trebuie să fie
împerecheat sau singur, dar nu trebuie să existe două procese care sunt vecine şi sunt
ambele neîmperecheate.
3) Arbore de acoperire. Sunt date n procese, fiecare corespunzând unui nod dintr-un
graf. Fiecare nod poate comunica doar cu vecinii săi. Scrieţi un program pentru
construirea arborelui de acoperire, fără a afla mai înainte topologia. Deci, fiecare
proces va decide împreună cu vecinii săi care legături să fie puse în arbore şi care nu.
4) Se dau trei procese, fiecare avand o secvenţă de numere întregi ordonată crescător.
Există cel puţin o valoare comună celor trei secvenţe. Scrieţi programul care găseşte
cea mai mică valoare comună.
96