Sunteți pe pagina 1din 101

Sisteme de timp real

C1 – Curs introductiv

1. Consideraţii generale privind sistemele de timp real

Sistemele de timp real cunosc o dezvoltare rapidă, atât sub aspectul complexităţii şi al
performanţelor, dar mai ales în ceea ce priveşte aria lor de răspândire. Aceasta este o consecinţă a
perfecţionării continue a structurilor integrate de tip embedded şi a creşterii siguranţei lor în
funcţionare.
Sistemele de timp real sunt în general sisteme on-line, conectate nemijlocit cu alte sisteme fizice
pe care le monitorizează şi le conduc. Prin urmare, datele de intrare sunt preluate direct din procesul
monitorizat, prin intermediul terminalelor, senzorilor, camerelor video etc., iar informaţia de
răspuns este transmisă direct în sistemului condus. Dacă sistemul de calcul preia datele de intrare
şi generează informaţia de răspuns într-un timp suficient de scurt pentru a putea controla
corespunzător desfăşurarea procesului, se spune că lucrează în timp real. Aşadar, caracteristica
principală a unui sistem de timp real este timpul de răspuns, care reflectă perioada necesară
sistemului pentru a genera un răspuns adecvat la un eveniment extern. Altfel spus, timpul de
răspuns este perioada dintre momentul producerii unei schimbări de stare în sistemul condus şi
momentul în care echipamentul de conducere generează un răspuns adecvat la această schimbare.
Dintre cerinţele de performanţă impuse sistemelor de timp real se disting două elemente, şi
anume:
• O viteză de reacţie corespunzătoare la schimbările de stare din proces – Sistemul trebuie să
asigure timpi de răspuns care să se încadreze în limite prestabilite, de cele mai multe ori deosebit
de severe.
• Siguranţă în funcţionare – Sistemele de timp real trebuie să aibă o fiabilitate ridicată şi o
securitate deosebită. De asemenea, trebuie să aibă capacitatea de a evita situaţiile critice şi de a
limita consecinţele unor defecţiuni grave. După o întrerupere accidentală sistemul trebuie să
permită o repunere cât mai repidă în funcţiune.
Se pot evidenţia două clase de sisteme de timp real cu caracteristici specifice, şi anume:
• Sisteme de monitorizare şi conducere a unor procese cu evoluție continuă și/sau discretă
(procese tehnologice sau alte procese similare);
• Sisteme tranzacţionale din sfera serviciilor.

1.1 Sisteme de timp real pentru conducerea proceselor


Sistemele de timp real pentru conducerea proceselor se întâlnesc la maşini automate şi linii de
fabricaţie, în sisteme de telecomunicaţie, în sisteme de distribuţie a energiei electrice, în sisteme de
dirijare a traficului rutier sau feroviar, în sisteme de pilotare automată, în sisteme de automatizare
de orice fel. Schema bloc a unui sistem de monitorizare şi conducere a unui proces este prezentată
în Fig. 1.

1
Fig. 1 - Schema bloc a unui sistem de conducere a unui proces

Prin funcţia de monitorizare se asigură înregistrarea oricărei schimbări importante de stare


din proces şi memorarea acestei informaţii atât timp cât este necesar. Procesul poate cuprinde atât
mărimi cu variaţie continuă sau analogice (ma), cât şi mărimi discrete (md). Informaţiile de stare din
proces sunt preluate fie prin explorare periodică – cum este cazul eşantionării semnalelor continue
folosind un convertor analog-numeric (CAN), fie asincron, după semnalarea unui eveniment extern
(ev) prin sistemul de întreruperi (SI). Ceasul de timp real (CTR) asigură controlul variabilei timp.
Datele sunt prelucrate pentru generarea de comenzi în proces sau pentru menţinerea unui “istoric”
privind evoluţia procesului.
Comenzile emise în proces pot fi discrete (cd), pentru închiderea sau deschiderea unor contacte,
semnalizarea unui eveniment etc., sau sub formă analogică (ca), de exemplu pentru generarea unei
mărimi de reglare prin intermediul unui convertor numeric-analogic (CNA) sau a unui modul PWM
pentru controlul motoarelor.
Sistemele de conducere a unor procese tehnologice complexe sunt în general sisteme
distribuite, organizate pe două niveluri: un nivel subordonat format din sisteme de conducere locală
dedicate unor procese fizice de sine stătătoare şi un nivel coordonator, cu rol de supervizare a
sistemelor locale. La nivel central se realizează o monitorizare permanentă a sistemelor locale şi se
actualizează o bază de date care să permită conducerea de ansamblu, pe termen lung, timp în care
criteriile de conducere se pot schimba (mai ales la nivel de parametri sau limite admisibile). Ca o
remarcă, sistemele locale nu comunică de regulă în mod direct, pentru a nu apărea conflicte
decizionale, ci prin intermediul calculatorului central cu rol de supervizare. Acesta poate fi privit mai
degrabă ca un sistem tranzacţional.
Pentru sistemele de conducere în timp real pot fi evidenţiate anumite caracteristici definitorii,
şi anume:
• Sistemul de întreruperi şi ceasul de timp real joacă un rol central şi de aceea trebuie să fie cât
mai performante;
• Cerinţele de timp de răspuns sunt de cele mai multe ori deosebit de severe;
• Sistemul poate să cuprindă un număr mare de interfeţe specializate, unele nestandardizate;
• Sistemul trebuie să aibă o structură flexibilă pentru o adaptare uşoară la posibile modificări în
procesul condus.

2
1.2 Sisteme tranzacţionale

Un sistem tranzacţional implică utilizarea unui număr mare de terminale de la care utilizatorii
introduc comenzi predefinite ca semnificaţie şi formate de introducere, numite tranzacţii, solicitând
efectuarea unor prelucrări şi afişarea rezultatelor într-un timp cât mai scurt. Sistemele
tranzacţionale se întâlnesc în sfera serviciilor. Ca exemple relevante pot fi menţionate: sistemele de
telefonie mobilă, sistemele ce deservesc reţele de bancomate sau cele care permit plata cu cardul,
sistemele pentru comerţul online etc. Structura funcţională a unui sistem tranzacţional este
prezentată în Fig. 2.

T1 Analizor
sintactic

cereri Pachet de rutine


Monitor de Baza
Ti pentru tratarea
(tranzactii) tranzactii de date
tranzactiilor
complexa

Tn

Fig. 2 ­ Structura unui sistem tranzacţional

Comenzile de la terminale sunt lansate în mod aleatoriu, iar performanţele de timp de răspuns
trebuie asigurate şi în condiţiile cele mai nefavorabile, când fluxul intrărilor este mare. Problemele
sunt legate de asigurarea unei capacităţi ridicate de prelucrare şi de gestiune a firelor de aşteptare.
Siguranţa datelor memorate pe arii de discuri este de asemenea esenţială.
Oganizarea corespunzătoare a aşteptării la nivelul monitorului de tranzacţii, fructificarea
paralelismului la nivelul unităţilor de prelucrare sau organizarea bazei de date astfel încât să se
reducă timpii de căutare au o importanţă deosebită pentru creşterea performanţelor de timp de
răspuns.

2. Particularităţi software pentru sistemele de timp real

Atât în sistemele de conducere a proceselor cât şi în sistemele tranzacţionale, aplicaţiile de timp


real sunt alcătuite din mai multe entităţi de sine stătătoare, numite procese sau taskuri, care
realizează funcţii specifice şi care pot fi executate în paralel, în mod concurent. Divizarea
programului de conducere într-un ansamblu de procese de sine stătătoare este impusă de
necesitatea asigurării cerinţelor de timp de răspuns şi de necesitatea simplificării proiectării
aplicaţiilor, pentru care trebuie să se asigure fiabilitate şi flexibilitate ridicată. Condiţiile de timp de
răspuns nu pot fi îndeplinite printr-un program complex şi greoi, în care sunt reunite toate funcţiile
necesare, ci printr-un sistem flexibil de procese de sine stătătoare, care să permită activarea unor
programe dedicate numai atunci când evenimentele din proces o impun.

3
Paralelismul în executarea proceselor concurente semnifică faptul că la un moment dat pot fi
active (începute şi neterminate) mai multe taskuri care concurează pentru obţinerea resurselor
necesare executării lor. Concurenţa ridică probleme de alocare a resurselor comune (unitate
centrală, memorie, variabile comune, fişiere partajate etc.) şi de evitare a situaţiilor de interblocaj
ce ar putea apărea.
În aplicaţiile de timp real trebuie identificate toate situaţiile critice din punct de vedere al
timpului de răspuns, pentru fiecare eveniment important. Referitor la restricţiile de timp de răspuns,
pentru unele evenimente limita se impune asupra valorii medii (o restricţie mai puţin severă), dar
pentru alte evenimente, orice valoare a timpului de răspuns nu trebuie să depăşească o valoare
limită impusă.
Un ansamblu de programe pentru o aplicaţie de timp real complexă are următoarele
caracteristici generale:
• Este compus dintr-un număr mare de procese de sine stătătoare. Interacţiunea între programele
concurente este foarte intensă, aceastea fiind părţi ale aceleiaşi aplicaţii;
• Trebuie să facă faţă unor cerinţe severe de timp de răspuns;
• Trebuie să asigure o mare siguranţă în funcţionare deoarece o eroare în realizarea funcţiilor
specifice poate conduce la efecte grave, uneori inacceptabile;
• Trebuie să asigure interfaţa cu o gamă largă de dispozitive externe;
• Trebuie să aibă capacitatea de evitare a situaţiilor de avarie la apariţia unei erori şi să asigure o
reluare facilă a procesului după remediere;
• Trebuie să aibă fiabilitate şi disponibilitate ridicată;
• Trebuie să fie flexibil pentru adaptarea la posibile modificări în proces.
Asigurarea unei fiabilităţi ridicate impune aplicarea unor tehnici de lucru în spiritul programării
defensive (engl. defensive programming), de preîntâmpinare a apariţiei erorilor. De asemenea,
pentru aplicaţii deosebite trebuie implementate tehnici de toleranţă la erori. Grija pentru reducerea
timpului de răspuns trebuie să fie permanentă. De remarcat că implementarea toleranţei la erori
poate afecta semnificativ performanţele de timp de răspuns, ceea ce impune găsirea unor soluţii de
compromis care să aibă în vedere siguranţa în funcţionare, pe de o parte, şi restricţiile de timp de
răspuns, pe de altă parte.
Cursul este structurat în două părţi: prima partea tratează problematica fiabilităţii şi siguranţei
în funcţionare, iar partea a doua este dedicată programării concurente specifice aplicaţiilor de timp
real.

4
3. Fiabilitatea şi siguranţa în funcţionare

3.1. Noţiuni de bază

Termenul de fiabilitate se referă la capacitatea unui sistem de a-şi conserva în timp proprietăţile
iniţiale, de a nu se defecta, în condiţii de exploatare corespunzătoare. Din punct de vedere cantitativ,
fiabilitatea reprezintă probabilitatea ca sistemul să-şi conserve starea de bună funcţionare de la
început într-un interval de timp specificat. Fiabilitatea este o cerinţă importantă pentru orice sistem
tehnic, dar pentru unele sisteme de mare importanţă funcţională o fiabilitate înaltă este o cerinţă
esenţială.
În general, sunt două posibilităţi complementare de creştere a fiabilităţii unui sistem complex.
O primă cale este aceea a simplificării structurii şi a folosirii unor componente de calitate superioară.
Practica a arătat însă că numai pe această cale fiabilitatea unui sistem complex nu poate fi crescută
oricât de mult, nici măcar pe intervale scurte de timp. Oricât de fiabile ar fi componentele, defecte
tot pot apărea ca urmare a unor perturbaţii mai severe pentru regimul normal de funcţionare.
Aceasta a condus la o nouă abordare a problematicii fiabilităţii, bazată pe ideea că într-o anumită
măsură apariţia defectelor trebuie acceptată iar sistemul trebuie să fie capabil să tolereze prezenţa
lor. Ca urmare, cea de a doua cale de creştere a fiabilităţii este implementarea toleranţei la defecte
(engl. fault tolerance).
Toleranţa la defecte defineşte capacitatea unui sistem de a-şi menţine funcţionarea corectă la
apariţia anumitor defecte, fără o intervenţie din exterior. Toleranţa la defecte se obţine întotdeauna
printr-o suplimentare a părţii hardware şi/sau software. Pe lângă redundanţa hardware sau
software mai apare şi o redundanţă de date sau o redundanţă de timp (de exemplu, o structură de
discuri magnetice într-o configuraţie RAID).
Odată cu scăderea spectaculoasă a preţului circuitelor integrate, toleranţa la defecte este tot
mai mult implementată în sistemele digitale, ceea ce permite realizarea unor sisteme de înaltă
fiabilitate.
O altă cerinţă importantă pentru un sistem tehnic este mentenabilitatea. O mentenabilitate
ridicată presupune asigurarea prin proiectare a unei structuri modulare şi a unei testabilităţi facile
(engl. design for testability), existenţa unor instrumente de diagnosticare performante şi a unei
documentaţii de service adecvate, piese de schimb, personal de întreţinere calificat etc.
Conceptul de disponibilitate reuneşte aspectele legate de fiabilitate şi de mentenabilitate şi
exprimă probabilitatea ca un sistem să funcţioneze corect la un moment dat, indiferent dacă
anterior au avut loc defectări şi reparări. Astfel, pentru creşterea disponibilităţii unui echipament se
poate acţiona pentru reducerea defectărilor, pe de o parte, şi scăderea perioadei de remediere în
caz de defectare, pe de altă parte. Dacă se acceptă ipoteza staţionarităţii, disponibilitatea exprimă
procentul perioadelor de bună funcţionare. O disponibilitate mare se impune din considerente
economice.
La sistemele complexe, de mare răspundere funcţională, cele trei concepte sunt încă insuficiente
pentru a caracteriza capacitatea sistemului de a-şi îndeplini funcţiile sale specifice.

5
Pentru aceste sisteme este importantă şi securitatea (engl. safety) care exprimă capacitatea unui
sistem de a furniza numai rezultate corecte sau, altfel spus, de a evita o funcţionare defectuoasă.
Din punct de vedere cantitativ, securitatea este probabilitatea ca într-un interval de timp dat
sistemul să nu furnizeze rezultate greşite şi să nu genereze comenzi eronate. Pentru orice
echipament complex, a cărui defectare nu poate fi exclusă, o securitate înaltă nu poate fi atinsă
decât printr-o autotestare realizată în timpul funcţionării normale (engl. on-line testing).
Autotestarea poate fi implementată la nivelul sistemului în ansamblu sau la nivelul modulelor critice
din sistem. Ca o remarcă, unele elemente de autotestare se regăsesc la toate sistemele de calcul.
Două exemple sunt tipice: folosirea bitului de paritate la transmisiile seriale şi a codurilor de control
la memorarea datelor pe discul magnetic.
Siguranţa în funcţionare este un concept mai larg care reflectă fiabilitatea şi securitatea unui
echipament de mare importanţă, dar şi capacitatea acestuia de a evita situaţiile de avarie care ar
putea apărea în timpul funcţionării, sau de a limita consecinţele unei defectări grave. În cazul
apariţiei unui defect acesta trebuie detectat în mod automat şi suficient de repede pentru ca
procesul condus să fie dirijat într-o stare nepericuloasă. Ca exemplu, într-un sistem de dirijare a
traficului, în cazul unei defecţiuni la sistemul de control lămpile de semnalizare trebuie să arate
culoarea roşie pentru a se evita producerea de accidente în trafic. Siguranţa în funcţionare implică
şi o capacitate mare de refacere după eroare.
Mărimile legate de calitatea dinamică a unui sistem sunt reunite în conceptul de eficienţă globală
(engl. dependability). Pentru a exprima mai riguros aceste mărimi să specificăm mai întăi stările în
care în care poate evolua sistemul în perioada de exploatare.
• 𝑆𝑓𝑛 − Starea de funcţionare normală care cuprinde şi situaţiile în care deşi au apărut defecte
sistemul continuă să furnizeze rezultate corecte, în sensul că sistemul tolerează defectele
apărute.
• 𝑆𝑓𝑒 − Starea de funcţionare eronată în care sistemul furnizează rezultate greşite, deşi se crede
că funcţionează corect; este o stare periculoasă care trebuie evitată, pe cât posibil.
• 𝑆𝑚𝑝 − Stare de mentenanţă preventivă. Sistemul este oprit pentru o verificare amplă, când se
urmăreşte detectarea eventualelor defecte latente care ar putea să se manifeste într-un regim
de funcţionare mai sever. Se verifică atât partea de hardware cât şi cea de software, de obicei
în cadrul unor programe de verificare şi întreţinere periodică.
• 𝑆𝑚ℎ − Stare de mentenanţă corectivă a părţii hardware. Remedierea se poate face prin
intervenţia echipei de service sau prin reconfigurare automată.
• 𝑆𝑚𝑠 − Stare de mentenanţă a părţii de software. Se verifică consecinţele defectelor hardware
asupra software-ului. Are loc reconstituirea tuturor programelor şi aducerea lor la punctul de
întrerupere care să permită reluarea funcţionării procesului condus. Reconstituirea se poate
face manual sau automat.

Fie 𝑆𝑡(𝑡) starea sistemului la momentul 𝑡. Pe baza acestui model se definesc următoarele funcţii.

6
• Fiabilitatea 𝑅(𝑡) este probabilitatea ca sistemul să rămână în stare de bună funcţionare în
intervalul [0, 𝑡). Sau altfel, 𝑅(𝑡) este probabilitatea ca sistemul funcţional la momentul 0 să nu se
defecteze până la momentul t .

𝑅(𝑡) = prob(𝑆𝑡(𝜏) ∈ {𝑆𝑓𝑛 , 𝑆𝑚𝑝 }, ∀𝜏 ∈ [0, 𝑡)) . (1)

• Disponibilitatea 𝐷(𝑡) este probabilitatea ca sistemul să fie în stare de bună funcţionare la


momentul t .

𝐷(𝑡) = prob(𝑆𝑡(𝑡) = 𝑆𝑓𝑛 ). (2)

• Securitatea 𝒮(𝑡) este probabilitatea ca sistemul să nu furnizeze răspunsuri eronate şi să nu


genereze comenzi greşite în intervalul [0, 𝑡).

𝒮(𝑡) = prob(𝑆𝑡(𝜏) ≠ 𝑆𝑓𝑒 , ∀𝜏 ∈ [0, 𝑡)). (3)

• Mentenabilitatea hardware 𝑀ℎ (𝑡) este probabilitatea ca restabilirea părţii hardware, începută


la momentul 0, să se termine până la momentul 𝑡.
𝑀ℎ (𝑡) = 1 − prob(𝑆𝑡(𝜏) = 𝑆𝑚ℎ , ∀𝜏 ∈ [0, 𝑡)). (4)
• Mentenabilitatea software 𝑀𝑆 (𝑡) se defineşte în mod similar, şi anume
𝑀𝑆 (𝑡) = 1 − prob(𝑆𝑡(𝜏) = 𝑆𝑚𝑠 , ∀𝜏 ∈ [0, 𝑡)). (5)

Consideraţii finale: Importanţa fiecărei mărimi din sfera eficienţei globale depinde de tipul
sistemului şi de condiţiile specifice de exploatare. Astfel, pentru calculatoarele de uz general, de
exemplu, indicatorii mai folosiţi sunt fiabilitatea şi mentenabilitatea. Pentru reţelele de calculatoare
complexe, disponibilitatea exprimă cel mai bine cerinţele utilizatorilor. În cazul unor sisteme de
mare răspundere funcţională însă, cum ar fi sistemele informatice bancare sau sistemele de dirijare
a traficului, se impune înainte de toate o securitate deosebită.

7
Sisteme de timp real
C2 - Fiabilitatea şi siguranţa în funcţionare – continuare

1. Relaţia dintre mărimile din sfera fiabilităţii şi siguranţei în funcţionare

Între mărimile din sfera fiabilităţii şi siguranţei în funcţionare definite anterior există o strânsă
interdependenţă. Următoarele două exemple evidenţiază acest lucru.

E x e m p l u l 1. 1. Relaţia “fiabilitate – mentenabilitate”


Aşa cum s-a precizat anterior, indicatorul de disponibilitate acoperă atât aspectele legate de
fiabilitate cât şi cele care se referă la mentenabilitate. Prin urmare, acest indicator are sens numai
atunci când sistemul este reparabil. Pentru a înţelege mai bine acest concept şi pentru a evidenţia
legătura strânsă dintre fiabilitate şi mentenabilitate se prezintă următoarea problemă.
Fie un sistem de calcul integrat într-o aplicaţie de timp real de mare răspundere funcţională.
Pentru o disponibilitate mai ridicată, la sistemul în forma iniţială, neredundantă, s-au adăugat
facilităţi hardware şi software de diagnosticare automată. Performanţele acestei structuri adiţionale
cu rol de autotestare se exprimă prin gradul de acoperire a defectelor (engl. fault coverage) sau
probabilitatea detectării automate a unui defect apărut în sistem (𝑐). În cazul unei defectări
detectate automat, timpul de remediere a sistemului este 𝜏1 – timp necesar pentru comanda unui
nou modul. Dacă defectul nu poate fi detectat prin sistemul de autodiagnosticare atunci timpul
necesar pentru remediere este 𝜏2 > 𝜏1 , întrucât se impune diagnosticarea sistemului de o persoană
specializată şi apoi comanda unui nou modul. Rata medie a defectărilor la sistemul neredundant
este 𝜆, iar cea pentru sistemul autodiagnosticabil este 𝛼𝜆, 𝛼 > 1, datorită structurii suplimentare
pentru autotestare. Să analizăm dacă o astfel de soluţie de creştere a disponibilităţii este viabilă.
Pentru un calcul numeric se consideră valorile: 𝑐 = 0.9, 𝜏1 = 24ℎ, 𝜏2 = 72ℎ.
Analiza detaliată a problemei: Prin adăugarea structurii suplimentare de autotestare
complexitatea sistemului creşte şi, ca urmare, fiabilitatea este afectată. Coeficientul 𝛼 dă măsura
complexităţii structurii adiţionale de control în raport cu complexitatea sistemului de bază
(neredundant). Pe de altă parte, facilitatea de diagnosticare automată duce la creşterea
mentenabilităţii. Cu alte cuvinte, sistemul autodiagnosticabil se defectează mai des, dar se repară
mai repede. Disponibilitatea sistemului autodiagnosticabil este mai mare decât în cazul sistemului
neredundant atunci când pierderea în fiabilitate este mai mică decât câştigul obţinut prin creşterea
mentenabilităţii. Să analizăm cele două tendinţe contradictorii. În final trebuie să determinăm
valoarea coeficientului 𝛼 pentru care această soluţie de creştere a disponibilităţii este viabilă.
Rezolvare: Sistemul fiind reparabil, perioadele de funcţionare alternează cu cele de oprire
pentru remediere. Dacă perioada medie de funcţionare neîntreruptă este 𝑡𝑓𝑚 iar perioada medie de
remediere este 𝑡𝑟𝑚 , atunci disponibilitatea sistemului este dată de ralaţia
𝑡𝑓𝑚
𝐷=𝑡 ⋅ 100%. (1)
𝑓𝑚 +𝑡𝑟𝑚

1
1
Pentru sistemul neredundant, 𝑡𝑓𝑚 = 𝜆 iar 𝑡𝑟𝑚 = 𝜏2 . În cazul sistemului redundant, cu facilităţi
1
de diagnosticare automată, 𝑡𝑓𝑚 = 𝛼𝜆, iar 𝑡𝑟𝑚 = 𝑐𝜏1 + (1 − 𝑐)𝜏2 . Aşadar, pentru sistemul
neredundant, disponibilitatea este
𝑡𝑓𝑚 1/𝜆 1
𝐷𝑛𝑟 = 𝑡 = 1/𝜆+𝜏 = 1+𝜆𝜏 , (2)
𝑓𝑚 +𝑡𝑟𝑚 2 2

iar pentru sistemul redundant,


1
𝛼𝜆 1
𝐷𝑠𝑟 = 1 = 1+𝜆𝛼(𝑐𝜏 . (3)
+𝑐𝜏1 +(1−𝑐)𝜏2 1 +(1−𝑐)𝜏2 )
𝛼𝜆

Impunând condiţia 𝐷𝑠𝑟 > 𝐷𝑛𝑟 , rezultă inegalitatea

𝛼(𝑐𝜏1 + (1 − 𝑐)𝜏2 ) < 𝜏2 ,

din care se deduce condiţia cu privire la coeficientul de multiplicare 𝛼 pentru ca soluţia de creştere
a disponibilităţii să fie viabilă, şi anume:
𝜏2
𝛼< . (4)
𝑐𝜏1 +(1−𝑐)𝜏2

72
Cu valorile date, rezultă 𝛼 < 0,9⋅24+0,1⋅72 < 2,50. Ceea ce înseamnă că atât timp cât structura de
autodiagnosticare nu depăşeşte în complexitate sistemul neredundant cu mai mult de 50%, soluţia
propusă pentru creşterea disponibilităţii este viabilă. Se remarcă faptul că rata de defectare 𝜆 nu
intervine în relaţia finală.
În continuare, sunt evidenţiate anumite aspecte legate de sistemele cu structură suplimentară
de control pentru creşterea securităţii.

E x e m p l u l 1. 2 Relaţia “fiabilitate – securitate”


Se consideră un sistem autocontrolabil cu schema bloc din Fig. 1. Fie c gradul de acoperire a unui
defect la unitatea de bază, sau probabilitatea detectării automate a unui astfel de defect. Starea
sistemului este dată de stările celor două unităţi componente şi de valoarea semnalului de control,
„Funcţionare” sau „Oprire”. Unitatea de bază (𝑈𝐵 ) se poate afla în starea de bună funcţionare (𝐵𝐹),
de defectare detectabilă (𝐷𝐷) sau de defectare nedetectabilă (𝐷𝑁). Unitatea de control (𝑈𝐶 ) se
poate afla în starea de bună funcţionare (𝐵𝐹) sau de defectare (𝐷). Stările sistemului sunt
prezentate în Tabelul 1.

Intrãri •
Unitate • Iesiri
de bazã functionale

Unitate Semnal
de control de control

Fig. 1 − Circuit autocontrolabil.

2
Tabelul 1 − Stările sistemului autocontrolabil.

Semnal de Stare 𝑈𝐶
Stare 𝑈𝐵
control 𝐵𝐹 𝐷
𝐵𝐹 𝑆1 𝑆2
Funcţionare 𝐷𝐷 − 𝑆3
𝐷𝑁 𝑆4 𝑆5
𝐵𝐹 − 𝑆6
Oprire 𝐷𝐷 𝑆7 𝑆8
𝐷𝑁 − 𝑆9

Aşa cum rezultă din acest tabel, stările 𝑆3 , 𝑆4 şi 𝑆5 pot fi apreciate ca “periculoase”, starea 𝑆2 ca
“norocoasă”, iar 𝑆6 ca stare de “oprire abuzivă”.
Pentru sistemul redundant, starea de funcţionare normală în raport cu care se defineşte funcţia
de fiabilitate este 𝑆𝑓𝑛 = {𝑆1 , 𝑆2 }, iar starea de funcţionare eronată în raport cu care se defineşte
funcţia de securitate este 𝑆𝑓𝑒 = {𝑆3 , 𝑆4 , 𝑆5 }.
Fie 𝑝𝑖 (𝑡) probabilitatea ca sistemul să se afle în starea 𝑆𝑖 la momentul 𝑡:
𝑝𝑖 (𝑡) = prob(𝑆𝑡(𝑡) = 𝑆𝑖 ), 𝑖 = 1, 2, … , 9.
Să presupunem că pentru cele două module componente, 𝑈𝐵 şi 𝑈𝐶 , se cunosc funcţiile de
fiabilitate, 𝑅𝐵 (𝑡) şi respectiv, 𝑅𝐶 (𝑡). Pe baza lor se pot scrie următoarele relaţii cu privire la
probabilităţile de stare. Pentru simplificarea scrierii se renunţă la parametrul 𝑡 (fiind subînţeles).
𝑝1 = 𝑅𝐵 𝑅𝐶
𝑝4 = (1 − 𝑐)(1 − 𝑅𝐵 )𝑅𝐶
𝑝7 = 𝑐(1 − 𝑅𝐵 )𝑅𝐶
𝑝2 + 𝑝6 = 𝑅𝐵 (1 − 𝑅𝐶 ) (5)
𝑝3 + 𝑝8 = 𝑐(1 − 𝑅𝐵 )(1 − 𝑅𝐶 )
𝑝5 + 𝑝9 = (1 − 𝑐)(1 − 𝑅𝐵 )(1 − 𝑅𝐶 )
Se remarcă faptul că probabilităţile 𝑝2 , 𝑝3 şi 𝑝5 nu se pot disocia de probabilităţile 𝑝6 , 𝑝8 şi respectiv,
𝑝9 . Aşadar, în lipsa oricărei informaţii privind principiul de funcţionare şi structura unităţii de control,
modelul din Fig. 1 este prea general şi nu permite exprimarea funcţiei de fiabilitate 𝑅(𝑡), şi de
securitate 𝑆(𝑡), pe baza fiabilităţii elementelor componente, 𝑅𝐵 (𝑡) şi 𝑅𝐶 (𝑡). Modelul permite însă
o mai bună înţelegere a celor doi indicatori. Când unitatea de control are o securitate ridicată se
spune despre sistem că este autotestabil.
Dacă un sistem nu dispune de structuri suplimentare de control, atunci nivelul de securitate al
sistemului este dat de nivelul de fiabilitate. Când se urmăreşte un nivel de securitate peste nivelul
fiabilităţii, se impun structuri de autotestare care afectează însă fiabilitatea. Pentru a ilustra acest
aspect se consideră un circuit logic autotestabil realizat cu două circuite identice care funcţionează
în duplex, aşa cum se prezintă în figura următoare.

3
Circuit 1 • Iesire functionala
Intrãri •
(de baza)
Semnal de
control
Circuit 2
(de control)

Unitate de control

Fig. 2 − Circuit logic autotestabil.

Acceptând că probabilitatea de defectare cvasisimultană şi în acelaşi mod a celor două module


este neglijabilă, şi că datorită simplităţii fiabilitatea porţii sau-exclusiv are o valoare apropiată de 1,
rezultă că şi securitatea circuitului autotestabil este aproape 1. Dacă se consideră că cele două
circuite sunt identice, cu fiabilitatea 𝑅, fiabilitatea circuitului autotestabil este 𝑅𝑐𝑎 = 𝑅 2 𝑅𝑋𝑂𝑅 < 𝑅.
Aşadar, fiabilitatea sistemului autotestabil poate fi semnificativ mai mică decât a sistemul
neredundant. În concluzie, dacă se urmăreşte o securitate mai mare, peste nivelul de fiabilitate,
aceasta se obţine în dauna fiabilităţii. În practică trebuie găsită o soluţie de compromis pentru cele
două mărimi care devin astfel contradictorii. Ţinând cont de aceste aspecte, este bine ca acolo unde
este posibil facilităţile de control să se implementeze prin mijloace software.

2. Indicatori de fiabilitate

Din punct de vedere calitativ fiabilitatea defineşte capacitatea unui sistem de a funcţiona fără
eroare o perioadă de timp specificată, în condiţii de exploatare corespunzătoare. Evenimentul care
marchează încetarea capacităţii sistemului de a-şi îndeplini funcţiile sale specifice se numeşte
defectare. Să considerăm, aşadar, variabila aleatoare 𝑋 ce exprimă timpul de bună funcţionare până
la prima defectare. Pe baza acestei variabile aleatoare se definesc următorii indicatori de fiabilitate,
care reflectă într-o anumită formă fiabilitatea sistemului.
• Funcţia de fiabilitate 𝑅(𝑡) sau probabilitatea de bună funcţionare,
𝑅(𝑡) = prob(𝑋 > 𝑡). (6)
Se presupune că la momentul 0 sistemul era în stare de bună funcţionare. Pentru estimarea
experimentală a valorii funcţiei de fiabilitate 𝑅(𝑇), pentru o durată 𝑇 dată (𝑇 se mai numeşte durata
misiunii), se poate organiza următorul experiment. O populaţie statistică (suficient de mare)
formată din 𝑁0 sisteme identice este urmărită în intervalul de timp [0, 𝑇]. Să presupunem că din
cele 𝑁0 sisteme, 𝑁 au rămas în funcţiune şi 𝑛 s-au defectat. 𝑅(𝑇) se estimează cu relaţia
𝑁
𝑅̂ (𝑇) = 𝑁 . (7)
0

• Funcţia de nonfiabilitate 𝐹(𝑡) sau probabilitatea de defectare,


𝐹(𝑡) = prob (𝑋 < 𝑡) = 1 − 𝑅(𝑡). (8)
𝐹(𝑡) este funcţia de repartiţie a variabilei aleatoare 𝑋. Pentru o perioadă de timp 𝑇,
probabilitatea de defectare poate fi estimată cu relaţia
𝑛
𝐹̂ (𝑇) = 𝑁 . (9)
0

4
De remarcat că performanţele de fiabilitate ale unui sistem depind de durata misiunii 𝑇. Pentru
a evidenţia acest lucru, în Fig. 3 se prezintă funcţiile de fiabilitate pentru două sisteme, din care
rezultă că pentru durata 𝑇1 sistemul 1 este mai fiabil decât sistemul 2, iar pentru durata 𝑇2 , invers.

R(t)

1 R1(t)

R2(t)

t
T1 T2

Fig. 3 – Comparaţie privind fiabilitatea a două sisteme.

• Funcţia de frecvenţă 𝑓(𝑡) este densitatea de repartiţie a variabilei 𝑋.


Funcţia 𝑓(𝑡) exprimă frecvenţa relativă a defectărilor sau, altfel spus, viteza de scădere în timp
a fiabilităţii. În Fig. 4 sunt prezentate forme uzuale pentru funcţia 𝑓(𝑡).

f (t)

(3) (2)
(1)

Fig. 4 – Funcţii de frecvenţă.

Între funcţia de frecvenţă şi funcţia 𝐹(𝑡) sau 𝑅(𝑡) există relaţiile:


𝑓(𝑡) = 𝐹 ′ (𝑡) şi 𝑓(𝑡) = −𝑅 ′ (𝑡) (10)
Pentru estimarea valorii 𝑓(𝑇) se determină numărul de defectări Δ𝑛𝑇 în intervalul (𝑇, 𝑇 + Δ𝑇)
şi se aplică relaţia,
Δ𝑛 1
𝑓̂(𝑇) = Δ𝑇𝑇 ⋅ 𝑁 ℎ−1 . (11)
0

• Rata sau intensitatea defectărilor 𝑧(𝑡).


𝑓(𝑡)
𝑧(𝑡) = 𝑅(𝑡). (12)

Δ𝑛𝑇 1 𝑁0 Δ𝑛𝑇 1
𝑧̂ (𝑇) = ⋅𝑁 ⋅ = ⋅ 𝑁 ℎ−1 . (13)
Δ𝑇 0 𝑁 Δ𝑇

Pentru foarte multe situaţii întâlnite în practică, forma grafică a funcţiei z(t), cunoscută şi sub
numele de „cadă de baie”, arată ca în Fig. 5. În această figură, zona I reflectă perioada de rodaj,
zona II corespunde perioadei de exploatare normală, iar zona III indică perioada în care se face
simţită uzura fizică.
5
z(t)

I II III

t
t1 t2

Fig. 5 – Forma uzuală a graficului funcţiei 𝑧(𝑡).

Se poate arăta că între 𝑧(𝑡) şi 𝑅(𝑡) există relaţia,


𝑡
𝑅(𝑡) = 𝑒 − ∫0 𝑧(𝜏)𝑑𝜏 . (14)
În zona a II-a de exploatare a unui sistem, repartiţia tipică pentru timpul de bună funcţionare
este cea exponenţial-negativă, pentru care 𝑓(𝑡) = 𝜆𝑒 −𝜆𝑡 şi 𝑅(𝑡) = 𝑒 −𝜆𝑡 . Exprimând funcţia de
fiabilitate sub forma
𝑡
𝑅(𝑡) = 𝑒 − ∫0 𝜆𝑑𝜏 . (15)
Rezultă că 𝑧(𝑡) este constantă, în concordanţă cu graficul arătat.
• Media timpului de bună funcţionare 𝑀𝑇𝐵𝐹, sau timpul mediu între defectări (engl. Mean Time
Between Failures),
∞ ∞ ∞ ∞
𝑀𝑇𝐵𝐹 ≝ ∫0 𝑡𝑓(𝑡) 𝑑𝑡 = − ∫0 𝑡𝑅 ′ (𝑡)𝑑𝑡 = −𝑡𝑅(𝑡) | + ∫0 𝑅(𝑡)𝑑𝑡.
0
Întrucât 𝑅(𝑡) tinde la 0 mai repede decât 𝑡 tinde la ∞, rezultă

𝑀𝑇𝐵𝐹 = ∫0 𝑅(𝑡)𝑑𝑡. (16)
Experimental, timpul mediu de bună funcţionare se estimează cu relaţia
̂ = 1 ∑𝑁
𝑀𝑇𝐵𝐹 0
𝑁 𝑖=1 𝑋𝑖 .
0
(17)

În practică indicatorii cei mai utilizaţi sunt 𝑧(𝑡) şi 𝑀𝑇𝐵𝐹.


Observaţie. Dacă se cunoaşte unul din indicatorii 𝑅(𝑡), 𝐹(𝑡), 𝑓(𝑡) sau 𝑧(𝑡) ceilalţi se pot deduce din
cel cunoscut.

6
Sisteme de timp real
C3 – Modele de evaluare a fiabilităţii

3. Modele de evaluare a fiabilităţii sistemelor


Evaluarea performanţelor de fiabilitate pentru un sistem presupune determinarea expresiei
funcţiei de fiabilitate 𝑅(𝑡), sau a valorii 𝑅(𝑇) pentru o durată a misiunii 𝑇 dată, pe baza indicatorilor
de fiabilitate ai elementelor componente. Analiza fiabilităţii unui sistem complex impune
parcurgerea următoarelor etape:
a) Adoptarea unui model de fiabilitate adecvat care să exprime corect relaţia dintre fiabilitatea
sistemului şi fiabilitatea elementelor sale componente;
b) Stabilirea metodei de analiză a fiabilităţii în funcţie de modelul adoptat;
c) Evaluarea propriu-zisă a fiabilităţii, pe baza modelului de fiabilitate ales şi a datelor privind
fiabilitatea elementelor componente (date obţinute din cataloage şi normative de fiabilitate, din
încercări de fiabilitate etc).
Pe tot parcursul acestei lucrări evaluarea performanţelor de fiabilitate se bazează pe ipoteza
independenţei defectărilor elementelor componente. De asemenea, în studiile analitice se
presupune că ratele de defectare ale componentelor sistemului sunt constante în timp, ceea ce
înseamnă că pentru timpii de bună funcţionare se admit repartiţii exponenţial-negative.

3.1. Modelul de fiabilitate serie

Modelul de fiabilitate serie este cel mai simplu şi, totodată, cel mai des întâlnit în practică
întrucât corespunde sistemelor neredundante, indiferent de structura lor. Caracteristic pentru un
sistem neredundant este faptul că defectarea oricărui element duce la căderea sistemului.
Modelul de fiabilitate serie este reprezentat în figura următoare. În această reprezentare, un
sistem se consideră în stare de bună funcţionare dacă un semnal ipotetic poate străbate structura
de la intrare (𝑖) la ieşire (𝑜).

R1 R2 Ri Rn
i • • o

Fig. 6 – Model de fiabilitate serie.

Fie 𝑋𝑖 variabila aleatoare ce exprimă timpul de bună funcţionare până la prima defectare a
elementului 𝑖 (𝑖 = 1, 2, … , 𝑛) şi 𝑋 variabila aleatoare compusă ce reprezintă timpul de bună
funcţionare a sistemului în ansamblu. Întrucât defectarea oricărui element duce la căderea
sistemului,
𝑋 = 𝑚𝑖𝑛{ 𝑋1 , 𝑋2 , … , 𝑋𝑛 }. (18)
Fie 𝑅𝑖 (𝑡) funcţia de fiabilitate a elementului 𝑖 (𝑖 = 1, 2, … , 𝑛). Întrucât buna funcţionare a
sistemului implică buna funcţionare a tuturor elementelor componente, funcţia de fiabilitate a
sistemului cu structură serie 𝑅𝑆 (𝑡) este dată de relaţia

1
𝑅𝑆 (𝑡) = ∏𝑛𝑖=1 𝑅𝑖 (𝑡) ≤ 𝑚𝑖𝑛{𝑅𝑖 (𝑡)}. (19)
𝑖

Când ratele de defectare ale elementelor componente sunt constante, notate cu 𝜆1 , 𝜆2 ,  , 𝜆𝑛 ,


funcţiile de fiabilitate sunt 𝑅𝑖 (𝑡) = 𝑒 −𝜆𝑖 𝑡 , 𝑖 = 1, 2, … , 𝑛. Ca urmare, funcţia de fiabilitate a
sistemului este

𝑅𝑆 (𝑡) = 𝑒 −𝜆𝑆 𝑡 , în care 𝜆𝑆 = ∑𝑛𝑖=1 𝜆𝑖 . (20)


Această relaţie evidenţiază cei doi factori care afectează după o tendinţă exponenţial-negativă
fiabilitatea unui sistem. Este vorba de complexitate (reflectată prin 𝜆𝑆 ) şi intervalul de timp
considerat (durata misiunii).
1
Pentru un element 𝑖, media timpului de bună funcţionare este 𝑀𝑇𝐵𝐹𝑖 = 𝜆 , în timp ce pentru
𝑖
1
sistemul în ansamblu, 𝑀𝑇𝐵𝐹 = 𝜆 , o valoare mai mică decât media timpului de bună funcţionare a
𝑆

oricărui element în parte.

3.2. Modelul de fiabilitate paralel

Modelul de fiabilitate paralel corespunde sistemelor cu redundanţă globală. Ca exemplu, poate


fi menţionat un sistem de discuri magnetice în configuraţie 𝑑𝑖𝑠𝑘 − 𝑚𝑖𝑟𝑟𝑜𝑟𝑖𝑛𝑔. Modelul este folosit
şi în studiul fiabilităţii sistemelor cu structură de tip reţea. În Fig. 7 este ilustrat acest model fiabilistic.

Rn

Ri
i • • • • o

R1

Fig. 7 – Model de fiabilitate paralel.

Aşa cum se prezintă în figură, caracteristic pentru un sistem cu structură fiabilistică de tip paralel
(indiferent de structura sa funcţională) este faptul că pentru buna funcţionare a sistemului este
suficientă funcţionarea doar a uneia dintre componente. Dacă 𝑋𝑖 exprimă timpul de bună
funcţionare până la prima defectare pentru componenta 𝑖 (𝑖 = 1, 2, … , 𝑛), iar 𝑋 este timpul de
bună funcţionare a sistemului în ansamblu, se poate scrie relaţia
𝑋 = max {𝑋1 , 𝑋2 , … , 𝑋𝑛 }. (21)
Prin urmare, fiabilitatea sistemului cu structură paralel este mai mare decât fiabilitatea oricăreia
dintre elementele sale. Pentru determinarea fiabilităţii sistemului este mai uşor să se opereze cu
probabilităţi de defectare. Astfel, funcţia de nonfiabilitate a sistemului redundant 𝐹𝑃 (𝑡) este
𝐹𝑝 (𝑡) = ∏𝑛𝑖=1 𝐹𝑖 (𝑡) (22)

în care 𝐹𝑖 (𝑡), 𝑖 = 1, 2, … , 𝑛, sunt funcţiile de nonfiabilitate pentru elementele componente.


Pentru funcţia de fiabilitate 𝑅𝑃 (𝑡) rezultă expresia
2
𝑅𝑝 (𝑡) = 1 − 𝐹𝑝 (𝑡) = 1 − ∏𝑛𝑖=1(1 − 𝑅𝑖 (𝑡)). (23)

Dacă elementele sunt identice, cu funcţia de fiabilitate 𝑅(𝑡), atunci


𝑅𝑃 (𝑡) = 1 − (1 − 𝑅(𝑡))𝑛 . (24)
Cel mai adesea sistemul este prevăzut cu o singură rezervă (𝑛 = 2). Funcţia de fiabilitate a sistemului
redundant este în acest caz:

𝑅𝑃 (𝑡) = 1 − (1 − 𝑅1 (𝑡))(1 − 𝑅2 (𝑡)) = 𝑅1 (𝑡) + 𝑅2 (𝑡) − 𝑅1 (𝑡)𝑅2 (𝑡) (25)

Dacă componentele sunt identice atunci 𝑅1 (𝑡) = 𝑅2 (𝑡) = 𝑅(𝑡) și relația se simplifică:

𝑅𝑃 (𝑡) = 1 − (1 − 𝑅(𝑡))2 = 2𝑅(𝑡) − 𝑅 2 (𝑡) = 𝑅(𝑡)(2 − 𝑅(𝑡)) ≥ 𝑅(𝑡). (26)

Aşa cum este ilustrat în Fig. 8, folosirea unei rezerve active asigură o creştere semnificativă a
fiabilităţii, dar cu un cost deosebit.

R(t)

1
Sistem redundant cu rezerva activa

Sistem neredundant (Simplex)

Fig. 8 – Creşterea fiabilităţii la un sistem cu structură paralel.

Pentru determinarea timpului mediu de bună funcţionare a unui sistem cu model de fiabilitate
paralel, compus din 𝑛 elemente identice cu rata medie de defectare 𝜆, se pleacă de la observaţia că
până la căderea sistemului sunt 𝑛 perioade distincte, notate 𝑌1 , 𝑌2 , … , 𝑌𝑛 , în care sistemul
funcţionează cu 𝑛 elemente, cu 𝑛 − 1 elemente, ş.a.m.d., în ultima perioadă, cu un singur element.
Variabila aleatoare 𝑋 este dată de relaţia
𝑋 = ∑𝑛𝑖=1 𝑌𝑖 . (27)
Să admitem că variabile aleatoare 𝑌1 , 𝑌2 , … , 𝑌𝑛 au repartiţii exponenţial-negative. Parametrii lor
sunt 𝑛𝜆, (𝑛 − 1)𝜆, … , 𝜆. Aplicând proprietatea de linearitate la calculul mediei, rezultă
1 1 1 𝐻𝑛
𝑀𝑇𝐵𝐹 = 𝑀[𝑋] = 𝑀[∑𝑛𝑖=1 𝑌𝑖 ] = ∑𝑛𝑖=1 𝑀[𝑌𝑖 ] = ∑𝑛𝑖=1 𝑖𝜆 = 𝜆 ∑𝑛𝑖=1 𝑖 = . (28)
𝜆

De exemplu, pentru 𝑛 = 2,
1 1 1.5
𝑀𝑇𝐵𝐹(𝑛=2) = (1 + 2) 𝜆 = , ceea ce înseamnă o creştere de 50% faţă de varianta
𝜆
neredundantă.
Dacă 𝑛 = 3,
1 1 1
𝑀𝑇𝐵𝐹(𝑛=3) = (1 + 2 + 3) 𝜆, ceea ce înseamnă că a doua rezervă aduce o creştere de 33,3%.

În concluzie, prima rezervă conduce la o creştere a 𝑀𝑇𝐵𝐹 cu 50% faţă de varianta neredundantă, a
doua rezervă, la o creştere cu 33,3%, a treia, la o creştere cu 25% ş.a.m.d.

3
3.3 Model de fiabilitate pentru sisteme cu rezerve pasive

Se consideră un sistem care funcţionează cu un modul de bază şi care mai are alte (𝑛 − 1)
module de rezervă identice, menţinute în stare pasivă. Rata medie de defectare a modulului în
funcţiune este 𝜆. Fiind pasive (nesolicitate), modulele de rezervă nu se pot defecta. Să presupunem
şi că înlocuirea unui modul defect cu altul de rezervă se face fără incident.
Dacă 𝑋𝑖 este timpul de bună funcţionare pentru modulul 𝑖, atunci timpul de bună funcţionare a
sistemului cu rezerve pasive este

𝑋 = ∑𝑛𝑖=1 𝑋𝑖 . (29)

Figura următoare ilustrează acest aspect.

𝑋1 𝑋2 𝑋3 ⋯ 𝑋𝑛−1 𝑋𝑛
𝑡
defectare
Fig. 9 – Evoluţia sistemului cu rezerve pasive până la defectare.

Când variabilele 𝑋𝑖 , 𝑖 = 1, 2, … , 𝑛, au repartiţie exponenţial-negativă de parametru 𝜆, atunci


variabila aleatoare compusă 𝑋 are o repartiţie 𝐸𝑟𝑙𝑎𝑛𝑔 de ordinul 𝑛, pentru care funcţia de repartiţie
este
(𝜆𝑡)𝑖
𝐹(𝑛, 𝜆, 𝑡) = 1 − ∑𝑛−1
𝑖=0 𝑒 −𝜆𝑡 . (30)
𝑖!

Ca urmare, funcţia de fiabilitate a sistemului studiat este

(𝜆𝑡)𝑖
𝑅𝑃 (𝑡) = ∑𝑛−1
𝑖=0 𝑒 −𝜆𝑡 . (31)
𝑖!

De remarcat că expresia (30) cuprinde primii 𝑛 termeni ai repartiţiei Poisson de parametru 𝜆𝑡.
Explicaţia este simplă. Ţinând cont de dualismul dintre o variabilă aleatoare continuă cu repartiţie
exponenţial-negativă şi o variabilă aleatoare discretă cu repartiţie Poisson, rezultă că fluxul
defectărilor produse în sistemul redundant este un flux poissonian de parametru 𝜆. Fie 𝑁(𝜆, 𝑡)
variabila aleatoare discretă care exprimă numărul defectărilor produse în sistem în intervalul de
timp [0, 𝑡). Astfel, probabilitatea ca în intervalul specificat numărul defectărilor să fie 𝑖 este dat de
relaţia:
(𝜆𝑡)𝑖
𝑃𝑟𝑜𝑏 (𝑁(𝜆, 𝑡) = 𝑖) = 𝑒 −𝜆𝑡 , 𝑖 = 0, 1, … , 𝑛 − 1, 𝑛. (32)
𝑖!

Sistemul redundant are 𝑛 variante de succes: când nu se produce nicio defectare în intervalul de
timp [0, 𝑡), sau când numărul de defectări este mai mic decât 𝑛 (doar cu ultima defectare se produce
şi căderea sistemului). Prin urmare, sumând primii 𝑛 termeni ai repartiţiei Poisson de parametru 𝜆𝑡
se obţine expresia (30).
Pentru un sistem cu o singură rezervă (𝑛 = 2), funcţia de fiabilitate este

𝑅𝑠𝑟 (𝑡) = 𝑒 −𝜆𝑡 + 𝜆𝑡𝑒 −𝜆𝑡 . (33)

4
Creşterea fiabilităţii este ilustrată în figura următoare.

R(t)

1 Sistem redundant cu rezerva pasiva

Sistem neredundant (Simplex)

Fig. 9 – Creşterea fiabilităţii prin adăugarea unei rezerve pasive.

Pentru un sistem cu două rezerve (𝑛 = 3), funcţia de fiabilitate este


(𝜆𝑡)2
𝑅(𝑡) = 𝑒 −𝜆𝑡 + 𝜆𝑡𝑒 −𝜆𝑡 + 𝑒 −𝜆𝑡 . (34)
2

În ceea ce priveşte media timpului de bună funcţionare (𝑀𝑇𝐵𝐹) aceasta este de 𝑛 ori mai mare faţă
de varianta neredundantă. Într-adevăr,
𝑛
𝑀𝑇𝐵𝐹 = 𝑀[𝑋] = 𝑀 [∑𝑛𝑖=1 𝑋𝑖 ] = ∑𝑛𝑖=1 𝑀[𝑋𝑖 ] = 𝜆 . (35)

3.4 Structuri de fiabilitate serie-paralel

Redundanţa globală este adesea costisitoare şi de aceea în multe cazuri se asigură elemente de
rezervă doar pentru componentele cu fiabilitate mai mică, sau cu poziţie cheie în sistem. Pentru
aceste sisteme modelul de fiabilitate are o structură serie­paralel, iar funcţia de fiabilitate se obţine
aplicând succesiv regulile anterioare.
În figura următoare (Fig. 10) sunt date câteva exemple. Pentru simplificarea scrierii funcţiei de
fiabilitate se renunţă la argumentul 𝑡, ca fiind implicit.

R2

R1 𝑅𝑆𝑃 = 𝑅1 (1 − (1 − 𝑅2 )(1 − 𝑅3 ))
• • •

= 𝑅1 (𝑅2 + 𝑅3 − 𝑅2 𝑅3 )
R3 = 𝑅1 𝑅2 + 𝑅1 𝑅3 (1 − 𝑅2 ) .

a)
R1 R3

• • • • • 𝑅𝑆𝑃 = (1 − (1 − 𝑅1 )(1 − 𝑅2 )) × (1 − (1 − 𝑅3 ) (1 − 𝑅4 ))
= (𝑅1 + 𝑅2 (1 − 𝑅1 )) × (𝑅3 + 𝑅4 (1 − 𝑅3 ))
R2 R4

b)

5
R1 R3

• • • • 𝑅𝑃𝑆 = 1 − (1 − 𝑅1 𝑅3 )(1 − 𝑅2 𝑅4 )
= 𝑅1 𝑅3 + 𝑅2 𝑅4 (1 − 𝑅1 𝑅3 ).
R2 R4

c)
R2

R1 R3
• • • •
𝑅𝑆𝑃 = 𝑅1 (1 − (1 − 𝑅2 )(1 − 𝑅3 )(1 − 𝑅4 ))
R4

d)

Fig. 10 – Structuri de fiabilitate serie-paralel.

În toate cazurile considerate rezervele sunt menţinute în stare activă, fiind solicitate în aceeaşi
măsură cu modulul de bază. Aceasta permite ca la nevoie comutarea pe rezervă să se facă imediat
sau într-un timp foarte scurt. Se admite că operaţia de comutare pe rezervă se face fără incident şi
de aceea comutatorul nu se reflectă în modelul de fiabilitate. Cazul cu rezervă pasivă sau cu
comutator imperfect va fi studiat ulterior, modelul serie-paralel nefiind adecvat.

Temă de casă (Tema 1):


1) Să se compare algebric fiabilitatea structurilor b) şi c) în condiţiile în care toate componentele
ar avea aceeaşi fiabilitate (𝑅). Să se explice calitativ rezultatul obţinut.
2) Pentru un anumit interval de timp, la structura b) valorile de fiabilitate sunt: 𝑅1 = 𝑅2 = 0.75,
iar 𝑅3 = 𝑅4 = 0.5. La structura d) fiabilitatea componentelor este: 𝑅1 = 0.75, iar 𝑅2 = 𝑅3 =
𝑅4 = 0.5. Să se verifice prin calcul numeric care din cele două structuri are o fiabilitate mai
ridicată. Să se încerce o explicaţie pentru rezultatul obţinut.

6
Sisteme de timp real

C4 – Modele de structuri cu redundanţă triplu modulară

3.5 Model cu redundanţă statică triplu modulară (𝑻𝑴𝑹)

Pentru sistemele de mare răspundere funcţională, cu durata misiunii limitată, o tehnică des
folosită pentru asigurarea unei fiabilităţi înalte constă în implementarea unei structuri cu
redundanţă statică triplu modulară (𝑇𝑀𝑅 – engl. Triple Modular Redundancy). Cum arată şi numele,
trei module compatibile 𝑀1 , 𝑀2 , 𝑀3 funcţionează în paralel, iar valoarea de ieşire este stabilită de
un bloc de decizie, numit 𝑣𝑜𝑡𝑒𝑟, care lucrează pe principiul logicii majoritare 2 din 3. Această
structură este prezentată în figura următoare (Fig. 11).

y1
M1

x y2 z
M2 V

y3
M3

Fig. 11 – Structura 𝑇𝑀𝑅.

Pentru circuite logice cu o singură ieşire, structura blocului de decizie este analizată în
continuare. Tabelul de adevăr pentru funcţia logică de ieşire 𝑧 şi diagrama V-K pentru sinteza acestei
funcţii sunt următoarele:

Tab. 1 - Tabelul de adevăr pentru


funcţia de ieşire
𝑦2
𝑦1 𝑦2 𝑦3 𝑧
0 1 0 0
0 0 0 0
0 0 1 0 𝑦1 1 1 1 0
0 1 0 0
0 1 1 1 𝑦3
1 0 0 0
1 0 1 1
Fig. 12 –
1 1 0 1
1 1 1 1 Diagrama V-K pentru funcţia 𝑧 = 𝑓(𝑦1 , 𝑦2 , 𝑦3 )

Pe baza diagramei V-K rezultă expresia logică 𝑧 = 𝑦1 𝑦2 + 𝑦2 𝑦3 + 𝑦1 𝑦3 = ̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅


𝑦1 𝑦2 ̅̅̅̅̅̅
̅̅̅̅̅̅ 𝑦2 𝑦3 ̅̅̅̅̅̅
𝑦1 𝑦3 , aşa
încât structura voter-ului poate fi de forma:

𝑦1 y1

𝑦2
𝑧 y2 z

𝑦3 y3

a) b)
Fig. 13 – Structură de voter pentru circuite cu o singură ieşire.

1
Se verifică uşor că dacă la intrările logice sunt cel puţin două valori de 1, la ieşirea voterului se
obţine 1, iar dacă sunt cel puţin două valori de 0, la ieşire se obţine 0.
Cel mai adesea modulele sunt identice. Fie 𝑅(𝑡) funcţia de fiabilitate a unui modul. Pentru
calculul fiabilităţii acestei structuri să presupunem mai întâi că voterul este ideal. Având în vedere
că structura 𝑇𝑀𝑅 poate tolera defectarea unui modul din cele trei, oricare ar fi acesta, funcţia de
fiabilitate poate fi exprimată cu relaţia:

𝑅𝑇𝑀𝑅 (𝑡) = 𝑅 3 (𝑡) + 3𝑅 2 (𝑡)(1 − 𝑅(𝑡)) = 3𝑅 2 (𝑡) − 2𝑅 3 (𝑡). (32)

Impunând ca 𝑅𝑇𝑀𝑅 (𝑡) ≥ 𝑅(𝑡), rezultă condiţia 3𝑅(𝑡) − 2𝑅 2 (𝑡) ≥ 1. Cum pentru ecuaţia de
gradul al II-lea care rezultă (−2𝑅 2 + 3𝑅 − 1 = 0), rădăcinile sunt 𝑅1 = 0.5 şi 𝑅2 = 1, pentru
îndeplinirea condiţiei impuse este necesar ca 𝑅(𝑡) ≥ 0,5. Aşa cum se arată şi în Fig. 14, structura
𝑇𝑀𝑅 asigură o creştere a fiabilităţii numai pentru o perioadă limitată de timp [0, 𝑡0 ).
𝑙𝑛 2 0,7
Dacă 𝑅(𝑡) = 𝑒 −𝜆𝑡 , impunând condiţia ca 𝑅(𝑡0 ) = 0.5 rezultă că 𝑡0 = ≈ .
𝜆 𝜆

R(t)

TMR
1

Sistem neredundant
0,5

t
t0

Fig. 14 – Funcţiile de fiabilitate 𝑅(𝑡) şi 𝑅𝑇𝑀𝑅 (𝑡).

Dacă se are în vedere şi posibilitatea de defectare a voterului şi se consideră 𝑅𝑉 (𝑡) funcţia de


fiabilitate a acestuia, rezultă

𝑅𝑇𝑀𝑅 (𝑡) = 𝑅𝑉 (𝑡)(3𝑅 2 (𝑡) − 2𝑅 3 (𝑡)) . (33)

Să analizăm timpul mediu de bună funcţionare pentru o structură 𝑇𝑀𝑅. Dacă voterul este ideal
iar pentru cele trei module 𝑅(𝑡) = 𝑒 −𝜆𝑡 , rezultă relaţia:
∞ ∞ 3 2 5 1
𝑀𝑇𝐵𝐹𝑇𝑀𝑅 = ∫0 3𝑒 −2𝜆𝑡 𝑑𝑡 − ∫0 2𝑒 −3𝜆𝑡 𝑑𝑡 = 2𝜆 − 3𝜆 = 6𝜆 < 𝜆. (34)

∞ 1 ∞ 1 1
𝑃𝑟𝑒𝑐𝑖𝑧𝑎𝑟𝑒: S-a aplicat relaţia de calcul: ∫0 𝑒 −𝑘𝜆𝑡 𝑑𝑡 = − 𝑘𝜆 𝑒 −𝑘𝜆𝑡 | = 0 − (− 𝑘𝜆) = 𝑘𝜆.
0
Pentru verificare, să analizăm evoluţia structurii 𝑇𝑀𝑅 până la defectare, aşa cum se prezintă în
figura următoare (Fig. 15).

𝑆1 𝑆2 𝑆3
3𝜆 2𝜆
3M 2M M

Fig. 15 – Evoluţia structurii 𝑇𝑀𝑅 până la defectare.

2
Stările de bună funcţionare sunt 𝑆1 şi 𝑆2 . Plecând de la timpul mediu de menţinere a sistemului în
fiecare stare de bună funcţionare, rezultă relaţia:
1 1 5
𝑀𝑇𝐵𝐹𝑇𝑀𝑅 = 3𝜆 + = 6𝜆 .
2𝜆

Relaţia (34) arată faptul că la structura 𝑇𝑀𝑅 timpul mediu de bună funcţionare se reduce cu
aproximativ 16% faţă de varianta neredundantă. Reducerea este şi mai importantă în cazul realist
cu voter imperfect. Ca urmare, tehnica 𝑇𝑀𝑅 trebuie aplicată numai pentru sisteme cu durata
misiunii limitată, nu şi pentru sisteme de folosinţă îndelungată.
Tehnica 𝑇𝑀𝑅 este folosită şi pentru creşterea fiabilităţii programelor. Astfel, trei echipe de
programatori realizează în mod independent variante diferite de program plecând de la specificaţii
comune. Pentru stabilirea rezultatelor sunt rulate toate cele trei variante de program. Pe lângă
costul ridicat al implementării, trebuie remarcată şi redundanţa de timp care intervine la aplicarea
acestei tehnici de creştere a siguranţei în funcţionare.

3.6 Structură TMR cu facilităţi de control pentru aplicaţii critice

Reamintim faptul că o structură cu redundantă triplu modulară (TMR) are două neajunsuri
importante, şi anume:
- fiabilitatea structurii este mai mare decât a sistemului neredundant doar pe o durată limitată;
- media timpului de bună funcţionare este mai scăzută decât în cazul sistemului neredundant
cu cel puţin 16,6%.
Dacă la această structură se adaugă însă şi facilităţi de control atunci performanţele sistemului
redundant se îmbunătăţesc considerabil. Schema bloc a unei astfel de structuri redundante este
prezentată în figura următoare.

Fig. 15 – Structură 𝑇𝑀𝑅 cu facilități suplimentare de control

Activarea unui semnal de eroare 𝑒𝑖 , 𝑖 = 1,2, 3, marchează prima defectare produsă în sistem,
mai precis a modulului 𝑀𝑖 . La defectarea unui modul, sistemul îşi continuă funcţionarea normală ca
urmare a redundanţei, dar îşi pierde toleranţa la defectări. De aceea, se recomandă ca în timpul cel
mai scurt (la prima oprire sau, dacă nu este posibil, la prima revizie) să se înlocuiască modulul defect
pentru revenirea la starea de teleranţă de la început. Astfel, pentru structura 𝑇𝑀𝑅 se asigură o
fiabilitate şi o siguranţă în funcţionare deosebite. Să analizăm în continuare structura logicii de
3
control. La prima defectare ieşirea voter-ului nu este afectată. Ca urmare, aşa cum se arată în Fig.
16, pentru identificarea modulului defect se pot compara mărimile 𝑦1 , 𝑦2 , 𝑦3 cu ieşirea voterului,
luată ca referinţă. Să analizăm în continuare şi o altă variantă de implementare.
Sinteza logicii de control pe baza tabelei de adevăr
Să considerăm tabela de adevăr pentru logica adiţională de control, aşa cum este prezentată în
continuare.
Tabelul 1 – Tabela de adevăr pentru logica de control

𝑦1 𝑦2 𝑦3 𝑒1 𝑒2 𝑒3
0 0 0 0 0 0
0 0 1 0 0 1
0 1 0 0 1 0
0 1 1 1 0 0
1 0 0 1 0 0
1 0 1 0 1 0
1 1 0 0 0 1
1 1 1 0 0 0

Pe baza tabelului de adevăr se pot scrie următoarele expresii logice pentru mărimile de ieşire:

𝑒1 = ̅̅̅
𝑦1 𝑦2 𝑦3 + 𝑦1 ̅̅̅
𝑦2 ̅̅̅ 𝑦1 𝑦2 𝑦3 + 𝑦1 ̅̅̅
̅̅̅ 𝑦2 𝑦3 = ̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅
𝑦3 = ̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿ ̅̅̅̅̅̅̅̅̅̅
𝑦1 𝑦2 𝑦3 ∙ ̅̅̅̅̅̅̅̅̅̅
̅̅̅ 𝑦1 ̅̅̅
𝑦2 𝑦3

𝑒2 = 𝑦1 ̅̅̅𝑦
𝑦2 3 + ̅̅̅ 𝑦3 = ̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿
𝑦1 𝑦2 ̅̅̅ 𝑦1 ̅̅̅𝑦
𝑦2 3 + ̅̅̅
𝑦1 𝑦2 ̅̅̅ ̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅
𝑦3 = ̅̅̅̅̅̅̅̅̅̅
𝑦 𝑦2 3 ∙ ̅̅̅̅̅̅̅̅̅̅
1 ̅̅̅𝑦 𝑦1 𝑦2 ̅̅̅
̅̅̅ 𝑦3 (35)

𝑒3 = 𝑦1 𝑦2 ̅̅̅
𝑦3 + ̅̅̅
𝑦1 ̅̅̅𝑦 𝑦1 𝑦2 ̅̅̅
𝑦3 + ̅̅̅ 𝑦2 3 = ̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅̅
𝑦2 3 = ̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿
𝑦1 ̅̅̅𝑦 ̅̅̅̅̅̅̅̅̅̅
𝑦3 ∙ ̅̅̅̅̅̅̅̅̅̅
𝑦1 𝑦2 ̅̅̅ 𝑦1 ̅̅̅𝑦
̅̅̅ 𝑦2 3

Rezultă o structură logică care depinde doar de mărimile 𝑦1 , 𝑦2 , 𝑦3 aşa cum se prezintă în figura
următoare.
𝑦3
𝑀3

𝑥 𝑦2 𝑧
𝑀2 V

𝑦1
𝑀1

𝑒3 𝑒2 𝑒1

Fig. 16 – Logică de generare a semnalelor de control pentru structura 𝑇𝑀𝑅 (varianta II).

De precizat că această logică funcţionează corect numai până la momentul producerii primei
defectări. După acest moment logica de control trebuie dezactivată până la refacerea stării de
toleranţă de la început.
4
Temă pentru acasă:
1) Să se compare complexitatea celor două variante de implementare pentru a vedea care este
de preferat.
2) Care este deosebirea de fond între cele două variante de implementare?

3.7 Structuri TMR reconfigurabile

Fie o structură redundantă care funcţionează cu trei module identice într-un aranjament iniţial
de tip 𝑇𝑀𝑅. La defectarea unui modul, în funcţie de obiectivul urmărit, o mai mare fiabilitate sau o
siguranţă în funcţionare mai ridicată, se poate alege continuarea funcţionării în una din următoarele
două variante:
1) Continuarea funcţionării în mod clasic, cu un singur modul fără autotestare – variantă
numită 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥;
2) Continuarea funcţionării cu ambele module rămase funcţionale într-o structură
autotestabilă de mare siguranţă – variantă numită 𝑇𝑀𝑅/𝐷𝑢𝑝𝑙𝑒𝑥.
Să analizăm în continuare cele două structuri 𝑇𝑀𝑅 cu facilităţi de reconfigurare automată.

➢ Analiza fiabilităţii şi securităţii

1) Structura 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥

La o structură 𝑇𝑀𝑅, după defectarea unui modul, buna funcţionare a celorlalte două module
este strict necesară pentru buna funcţionare a sistemului. În consecinţă, în această perioadă cele
două module funcţionale trebuie privite ca elemente ale unui model de fiabilitate serie. De aceea,
este mai avantajos ca sistemul să continue operarea cu un singur modul funcţional, şi nu cu
amândouă. Acest argument privind îmbunătăţirea performanţelor de fiabilitate justifică realizarea
structurii reconfigurabile 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥. Vom arăta în cele ce urmează că fiabilitatea acestei
structuri este într-adevăr superioară structurii 𝑇𝑀𝑅.
Într-o primă analiză facem abstracţie de fiabilitatea structurii adiţionale de decizie, control şi
reconfigurare, concentrându-ne astfel doar asupra celor 3 module componente.
Fie 𝑋1 , 𝑋2 , 𝑋3 variabilele aleatoare ce exprimă timpii de bună funcţionare pentru cele trei
module componente 𝑀1 , 𝑀2 , 𝑀3 . Pentru modulul ales să asigure continuarea funcţionării
sistemului, după defectarea altui modul, fie 𝑊 restul de timp până la defectare. Cu 𝑋 se notează
timpul până la defectare pentru sistemul redundant în ansamblu. Trebuie menţionat că pentru
proiectarea structurii de reconfigurare, modulul ales să continue funcţionarea la defectarea altui
modul se stabileşte de la început. Să considerăm că la defectarea unuia din cele trei module
componente continuarea se va realiza după cum se prezintă în tabelul următor.

Tab. 2 - Specificaţii privind reconfiguarea sistemului

Modulul defect Modulul care continuă funcţionarea


𝑀1 𝑀3
𝑀2 𝑀1
𝑀3 𝑀2

5
Timpul de bună funcţionare a sistemului cu structură 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥 se exprimă sub forma:
𝑋 = 𝑚𝑖𝑛{ 𝑋1 , 𝑋2 , 𝑋3 } + 𝑊.
Figura următoarea ilustrează mai bine semnificaţia variabilelor aleatoare introduse.
𝑊
𝑋1

𝑋2 reconfigurare

𝑋3

𝑚𝑖𝑛{ 𝑋1 , 𝑋2 , 𝑋3 }
defectare

X
𝑋 𝑀 asigură continuarea funcţionării
a) 𝑀2 se defectează şi 1

𝑋1
𝑋2
𝑊
𝑋3

reconfigurare defectare
𝑚𝑖𝑛{ 𝑋1 , 𝑋2 , 𝑋3 }

X
𝑋
b) 𝑀1 se defectează şi 𝑀3 asigură continuarea funcţionării

Fig. 17 - Timpul de funcţionare (𝑋) pentru structura reconfigurabilă 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥.

Dacă considerăm variabilele 𝑋1 , 𝑋2 , 𝑋3 ca fiind independente şi admitem că fiecare are o


repartiţie exponenţial-negativă de parametru 𝜆, variabila aleatoare compusă 𝑚𝑖𝑛{ 𝑋1 , 𝑋2 , 𝑋3 } are
tot o repartiţie exponenţial-negativă dar de parametru 3𝜆. Mai mult, ţinând cont de proprietatea
variabilei aleatoare exponenţial-negative de a fi fără memorie, şi variabila aleatoare 𝑊 are tot o
astfel de repartiţie de parametru 𝜆. În consecinţă, variabila aleatoare compusă 𝑋 =
𝑚𝑖𝑛{ 𝑋1 , 𝑋2 , 𝑋3 } + 𝑊 are o repartiţie hipoexponenţială de parametri 3𝜆 şi 𝜆. Pentru o lege de
distribuţie hipoexponenţială de parametri 𝜆1 şi 𝜆2 , funcţia de repartiţie este de forma:
𝜆1 𝜆2
𝐹( 𝜆1 , 𝜆2 , 𝑡) = 1 − 𝜆 𝑒 −𝜆2 𝑡 − 𝜆 𝑒 −𝜆1𝑡 , 𝜆1 > 0, 𝜆2 > 0, 𝑡 ≥ 0 (36)
1 −𝜆2 2 −𝜆1

Prin urmare, funcţia de repartiţie pentru variabila aleatoare compusă 𝑋 ∈ 𝐻𝑖𝑝𝑜(3𝜆, 𝜆) are expresia,
3𝜆 𝜆 3 1
𝐹(𝜆, 𝑡) = 1 − 2𝜆 𝑒 −𝜆𝑡 + 2𝜆 𝑒 −3𝜆𝑡 = 1 − 2 𝑒 −𝜆𝑡 + 2 𝑒 −3𝜆𝑡 , 𝑡 ≥ 0. (37)

Funcţia de fiabilitate a structurii 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥 este aşadar


3 1
𝑅𝑇𝑀𝑅⁄𝑆 (𝑡) = 1 − 𝐹(𝜆, 𝑡) = 2 𝑒 −𝜆𝑡 − 2 𝑒 −3𝜆𝑡 = 1.5 𝑒 −𝜆𝑡 − 0.5 𝑒 −3𝜆𝑡 , 𝑡 ≥ 0. (38)

Este uşor de arătat că 𝑅𝑇𝑀𝑅/𝑆 (𝑡) ≥ 𝑅𝑇𝑀𝑅 (𝑡) şi 𝑅𝑇𝑀𝑅/𝑆 (𝑡) ≥ 𝑅(𝑡). Într-adevăr, renunţând la
parametrul 𝑡 pentru simplificarea scrierii, rezultă relaţiile:
𝑅𝑇𝑀𝑅/𝑆 − 𝑅𝑇𝑀𝑅 = 1.5𝑅 − 0.5𝑅 3 − (3𝑅 2 − 2𝑅 3 ) = 1.5𝑅 − 3𝑅 2 + 1.5𝑅 3

= 1.5𝑅(1 − 2𝑅 + 𝑅 2 ) = 1.5𝑅(1 − 𝑅)2 ≥ 0.


6
𝑅𝑇𝑀𝑅/𝑆 − 𝑅 = 1.5𝑅 − 0.5𝑅 3 − 𝑅 = 0.5𝑅 − 0.5𝑅 3 = 0.5𝑅(1 − 𝑅 2 ) ≥ 0.

În figura următoare se prezintă comparativ funcţiile de fiabilitate pentru structurile 𝑆𝑖𝑚𝑝𝑙𝑒𝑥, 𝑇𝑀𝑅
şi 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥.

R(t)

TMR
1
Simplex

0,5 TMR/simplex

Fig. 18 – Comparaţie privind fiabilitatea structurilor 𝑆𝑖𝑚𝑝𝑙𝑒𝑥, 𝑇𝑀𝑅 şi 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥.

Media timpului de bună funcţionare pentru structura 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥 se determină astfel :


1 1 4
𝑀𝑇𝐵𝐹 = 𝑀[𝑋] = 𝑀[𝑚𝑖𝑛{𝑋1 , 𝑋2 , 𝑋3 }] + 𝑀[𝑊] = 3𝜆 + 𝜆 = 3𝜆. (39)

Rezultă că 𝑀𝑇𝐵𝐹 pentru structura 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥 este cu aproximativ 33,3% mai mare faţă de
varianta neredundantă şi cu 60% mai mare faţă de structura 𝑇𝑀𝑅. Într-adevăr,

(4/3λ − 1/λ) / (1/λ)  100 = 1/3  100 =33.3%, iar (40)

(4/3λ-5/6λ) / (5/6λ)  100=3/6λ  6λ/5  100 = 3/5  100 = 60%.

Logica adiţională de decizie, control şi reconfigurare are o poziţie cheie în cazul acestui sistem
redundant, buna funcţionare a sa fiind strict necesară. Ca urmare, această logică trebuie considerată
în serie cu structura redundantă formată din cele trei module. Astfel, dacă considerăm şi funcţia de
fiabilitate a logicii de decizie, control şi reconfigurare notată cu 𝑅𝑑𝑐𝑟 (𝑡), putem scrie în final relaţia:

𝑅𝑇𝑀𝑅⁄𝑆 (𝜆, 𝑡) = (1.5 𝑒 −𝜆𝑡 − 0.5 𝑒 −3𝜆𝑡 )𝑅𝑑𝑐𝑟 (𝑡). (41)

În ceea ce priveşte funcţia de securitate, notată 𝒮𝑇𝑀𝑅⁄𝑆 (𝑡), trebuie remarcat faptul că structura
𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥 nu generează semnal suplimentar de control. Ca urmare, nivelul de siguranţă în
funcţionare este dat de nivelul fiabilităţii. Astfel,
𝒮𝑇𝑀𝑅⁄𝑆 (𝑡) = 𝑅𝑇𝑀𝑅⁄𝑆 (𝑡). (42)

2) Structura 𝑇𝑀𝑅/𝐷𝑢𝑝𝑙𝑒𝑥

La defectarea unuia dintre cele trei module componente din structura 𝑇𝑀𝑅, modulul defect este
dezactivat iar sistemul se reconfigurează automat așa încât cele două module rămase să funcţioneze
în duplex, în regim de mare siguranţă. Mai precis, cele două module funcţionale operează în paralel
iar ieşirile lor sunt comparate continuu. La apariţia unei diferenţe între cele două răspunsuri se
generează un semnal de eroare pentru oprirea controlată a sistemului.

7
În ceea ce priveşte partea redundantă, cu cele trei module componente, se remarcă faptul că
structura 𝑇𝑀𝑅/𝐷𝑢𝑝𝑙𝑒𝑥 tolerează tot un modul defect, oricare ar fi acesta, la fel ca la structura 𝑇𝑀𝑅
clasică. Logica de decizie, control şi reconfigurare trebuie să fie neapărat funcţională. Astfel,

𝑅𝑇𝑀𝑅⁄𝐷 (𝑡) = 𝑅𝑇𝑀𝑅 (𝑡)𝑅𝑑𝑐𝑟 (𝑡) = (3𝑅 2 (𝑡) − 2𝑅 3 (𝑡))𝑅𝑑𝑐𝑟 (𝑡). (43)

Dacă pentru modulele componente 𝑅(𝑡) = 𝑒 −𝜆𝑡 , atunci

𝑅𝑇𝑀𝑅⁄𝐷 (𝜆, 𝑡) = (3𝑒 −2𝜆𝑡 − 2𝑒 −3𝜆𝑡 )𝑅𝑑𝑐𝑟 (𝑡). (44)

Referitor la siguranţa în funcţionare, dacă se acceptă faptul că defectarea cvasisimultană şi în


acelaşi mod a celor două module din structura duplex este puţin probabilă şi poate fi neglijată,
rezultă că nivelul de securitate depinde de fiabilitatea logicii de decizie, control şi reconfigurare. Ca
urmare, putem scrie expresia:

𝒮𝑇𝑀𝑅⁄𝐷 (𝑡) = 𝑅𝑑𝑐𝑟 (𝑡). (45)

Cu aceste rezultate putem concluziona că structura 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥 oferă o fiabilitate mai


ridicată, în timp ce structura 𝑇𝑀𝑅/𝐷𝑢𝑝𝑙𝑒𝑥 asigură un nivel de siguranţă în funcţionare mai mare.
În funcţie de obiectivul urmărit, se adoptă una din cele două variante.
Temă de casă (𝑇2): Se consideră că rata defectare a logicii adiţionale de decizie, control şi
reconfigurare (𝜆𝑑𝑐𝑟 ) este de cinci ori mai redusă decât rata de defectare a unui modul. Să se compare
grafic funcţiile de fiabilitate şi respectiv funcţiile de securitate pentru structurile reconfigurabile
𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥 şi 𝑇𝑀𝑅/𝐷𝑢𝑝𝑙𝑒𝑥.

➢ Sinteza logicii de decizie, control şi reconfigurare automată

Pentru exemplificarea sintezei logicii de decizie, control şi reconfigurare, se consideră cazul mai
simplu în care sistemul studiat generează o singură ieşire logică. Această structură trebuie să
realizeze următoarele funcţii:
- să genereze un răspuns la ieşirea 𝑧 în funcţie de valorile furnizate de module funcţionale şi de
configuraţia impusă;
- să detecteze automat producerea primei defectări în structura 𝑇𝑀𝑅 şi să izoleze modulul defect;
- să reconfigureze structura redundantă pentru continuarea cu un singur modul sau în duplex,
după caz;
- pentru un regim de funcţionare în duplex, să semnaleze ca eroare atunci când cele două module
care operează în paralel nu mai generează răspunsuri identice.
În ceea ce priveşte detectarea automată a producerii unei defectări în structura 𝑇𝑀𝑅 şi
identificarea modului defect, se foloseşte o structură logică de control (𝑆𝐿𝐶) de tipul cei prezentate
anterior. Starea modulelor componente este reflectată de trei bistabile cu semnificaţia: 1 – bună
funcţionare, 0 – defectare. Bistabilele sunt la început în starea 1 logic iar activarea unui semnal de
eroare duce la resetarea bistabilului corespunzător. O dată cu prima defectare, starea bistabilelor
rămâne “îngheţată” până la remediere (cu un singur bistabil pe 0), pentru că structura nu poate
identifica corect o nouă defectare.

8
Pentru izolarea modulului defect, ieşirile modulelor (𝑦1 , 𝑦2 , 𝑦3 ) sunt validate de valorile
bistabilelor de stare. Se foloseşte în acest scop un nivel de porţi logice de validare de tip AND. Atunci
când un modul este defect, valoarea bistabilului de stare corespunzător este 0 logic şi semnalul
generat de modul nu se mai poate propaga şi nu mai poate influenţa ieşirea 𝑧.
În figurile următoare se prezintă logicile de decizie, control şi reconfigurare pentru cele două
structuri, 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥 şi 𝑇𝑀𝑅/𝐷𝑢𝑝𝑙𝑒𝑥, considerând module/circuite cu o singură ieşire.

Fig. 19 - Logica de decizie, control şi reconfigurare la 𝑇𝑀𝑅/𝑆𝑖𝑚𝑝𝑙𝑒𝑥


pentru circuite cu o singură ieşire.

Fig. 20 - Logica de decizie, control şi reconfigurare la 𝑇𝑀𝑅/𝐷𝑢𝑝𝑙𝑒𝑥


pentru circuite cu o singură ieşire.

Cele două figuri evidenţiază faptul că astfel de structuri reconfigurabile pot fi implementate în
multe aplicaţii, logica adiţională nefiind atât de complicată.

9
Sisteme de timp real

Cursul 5 – Structuri de memorie RAM cu coduri de control

În aplicaţiile critice, cerinţele privind fiabilitatea şi securitatea părții de memorie sunt severe şi
nu pot fi satisfăcute fără asigurarea într-o anumită măsură a toleranţei la defecte sau la erori. Sunt
două tehnici principial diferite de implementare a toleranţei la defecte / erori, şi anume:
a) Detectarea şi corectarea automată a erorilor de memorie folosind coduri suplimentare de
control (redundanţă pasivă);
b) Testarea 𝑜𝑛𝑙𝑖𝑛𝑒 a memoriei pentru detectarea cât mai rapidă a defectării unui modul şi
înlocuirea acestuia cu unul de rezervă (redundanţă activă sau de comutaţie).
Cele două tehnici nu se exclud, ci sunt complementare. Dacă nivelul de siguranţă în funcţionare
o impune, cele două tehnici de creştere a fiabilităţii şi securităţii memoriei RAM pot fi implementate
simultan: redundanţa pasivă la nivelul de bază şi redundanţa activă la un nivel superior.

Memorie RAM cu circuite de control pentru detectarea


şi corectarea automată a erorilor

Cea mai folosită metodă de creştere a fiabilităţii şi securităţii memoriei RAM se bazează pe coduri
suplimentare de control ce permit detectarea şi corectarea într-o anumită măsură a erorilor de
memorie. În cazul memoriilor RAM cele mai eficiente s-au dovedit a fi codurile 𝐻𝑎𝑚𝑚𝑖𝑛𝑔. Acestea
s-au impus deoarece logica combinaţională de formare a codurilor la scriere şi cea pentru controlul
şi corecţia erorilor la citire sunt mai simple. În implementările uzuale se folosesc două tipuri de
circuite de control, şi anume:
• SEC_SED (𝑆𝑖𝑛𝑔𝑙𝑒 𝐸𝑟𝑟𝑜𝑟 𝐶𝑜𝑟𝑟𝑒𝑐𝑡𝑖𝑛𝑔 – 𝑆𝑖𝑛𝑔𝑙𝑒 𝐸𝑟𝑟𝑜𝑟 𝐷𝑒𝑡𝑒𝑐𝑡𝑖𝑛𝑔);
• SEC_DED (𝑆𝑖𝑛𝑔𝑙𝑒 𝐸𝑟𝑟𝑜𝑟 𝐶𝑜𝑟𝑟𝑒𝑐𝑡𝑖𝑛𝑔 – 𝐷𝑜𝑢𝑏𝑙𝑒 𝐸𝑟𝑟𝑜𝑟 𝐷𝑒𝑡𝑒𝑐𝑡𝑖𝑛𝑔).
În cazul codurilor Hamming, pentru o memorie cu lungimea cuvântului de date 𝑚 = 2𝑥 biţi, sunt
necesari 𝑘 = 𝑥 + 1 biţi de control pentru SEC_SED şi 𝑘 = 𝑥 + 2 biţi pentru SEC_DED. În Tab. 1 se
prezintă numărul biţilor de control în funcţie de lungimea cuvântului de date. Memoria conţine
cuvinte extinse de lungime 𝑛, formate din 𝑚 biţi de date şi 𝑘 biţi de control (𝑛 = 𝑚 + 𝑘).

Tab. 1 – Structura cuvântului extins format din biţi de date şi biţi de control

Numărul biţilor Numărul biţilor de control (𝑘) Lungimea cuvântului extins (𝑛)
de date (𝑚) SEC_SED SEC_DED SEC_SED SEC_DED
4 3 4 7 8
8 4 5 12 13
16 5 6 21 22
32 6 7 38 39
64 7 8 71 72

1
Din Tab. 1 rezultă că ponderea biţilor de control în cuvântul extins scade pe măsură ce numărul
biţilor de date creşte. Structura sistemului de memorie RAM cu circuite de control pentru detecţia
şi corecţia automată a erorilor este prezentată în Fig. 1.

m biţi de date Memorie m biţi de date date


RAM
Control
extinsă
&
k biţi de control sindrom Corecţie
Logica de (cuvinte de Logica de m
codare date cu biţi decodare eroare
m+k (k biţi)
de control)

Fig. 1 – Structura memoriei RAM cu circuite de control.

În continuare sunt analizate structurile combinaţionale de codare, control şi corecţie pentru o


memorie RAM cu lungimea cuvântului de 4 biţi.

Notaţii folosite:
𝑎, 𝑏, 𝑐, 𝑑 – biţii de date furnizaţi de procesor la scrierea într-o locaţie de memorie;
𝑝, 𝑞, 𝑟, (𝑠) – biţii de control asociaţi biţilor de date 𝑎, 𝑏, 𝑐, 𝑑;
𝑎̃, 𝑏̃, 𝑐̃ , 𝑑̃, 𝑝̃, 𝑞̃, 𝑟̃ , (𝑠̃ ) – biţii citiţi din memorie din locaţia extinsă.

Structura circuitelor de control la codarea SEC_SED

I. Logica de codare
Biţii de control asociaţi biţilor de date se pot genera după după cum urmează:
𝑝 = 𝑏  𝑐  𝑑, 𝑞 =𝑎𝑐, 𝑟 =𝑎𝑏𝑑

a p
p = bcd
b
Cuvânt depus pe q Biţi de
magistrala de µP c q = acd
control
d
r
r = abd

Fig. 2 – Logica de codare la varianta SEC_SED.

Corespondenţa dintre biţii de date şi cei de control este prezentată în tabelul următor.

2
Tab. 2 – Mulţimea cuvintelor valide la codarea SEC_SED.

𝑎 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
𝑏 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
𝑐 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
𝑑 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
𝑝 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1
𝑞 0 1 1 0 0 1 1 0 1 0 0 1 1 0 0 1
𝑟 0 1 0 1 1 0 1 0 1 0 1 0 0 1 0 1
𝐶𝑜𝑑 𝑑𝑒 𝑐𝑜𝑛𝑡𝑟𝑜𝑙 0 7 6 1 5 2 3 4 3 4 5 2 6 1 0 7

Să analizăm distanţa de cod în acest caz. Reamintim că distanţa de cod în sens 𝐻𝑎𝑚𝑚𝑖𝑛𝑔
reprezintă numărul minim de biţi prin care două cuvinte valide diferă între ele. Plecând de la această
definiţie, o verificare completă presupune compararea celor 120 de perechi posibile de cuvinte
2
valide (𝐶16 ). Ne vom limita deocamdată la o verificare intuitivă a faptului că la această codare
distanţa 𝐻𝑎𝑚𝑚𝑖𝑛𝑔 este 3. Cum primul cuvânt conţine numai biţi de 0, celelalte cuvinte ar trebui
să aibă cel puţin 3 biţi de 1. Similar, cum ultimul cuvânt conţine numai biţi de 1, celelalte cuvinte ar
trebui să conţină cel puţin 3 biţi de 0. Prin urmare, cu excepţia primei şi ultimei coloane, toate
celelalte combinaţii trebuie să aibă 3 biţi de 0 şi 4 biţi de 1, sau invers. Acest lucru se verifică uşor în
Tab. 2. Vom reveni asupra importanţei acestui concept.

II. Logica de decodare


La citirea din memorie se verifică cuvântul extins şi se generează un cod de control format din 𝑘 biţi,
care se numeşte şi 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒. Biţii din 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒 se generează după următoarele relaţii:
𝑢2 = 𝑏̃  𝑐̃  𝑑̃  𝑝̃ , 𝑢1 = 𝑎̃  𝑐̃  𝑑̃  𝑞̃, 𝑢0 = 𝑎̃  𝑏̃  𝑑̃  𝑟̃
Aşadar, controlul se face astfel: asupra biţilor de date citiţi din memorie se aplică aceeaşi relaţie
de calcul ca la scriere, iar rezultatul se compară cu bitul de control corespunzător din cuvântul
extins. Dacă cuvântul citit este fără eroare, adică este identic cu cuvântul scris anterior în memorie
(𝑎̃ = 𝑎, 𝑏̃ = 𝑏, . .. , 𝑟̃ = 𝑟) atunci toţi biţii de control sunt 0. Exemplificare pentru bitul 𝑢2 :
𝑢2 = 𝑏̃  𝑐̃  𝑑̃  𝑝̃ = 𝑏  𝑐  𝑑  𝑝 = 𝑏  𝑐  𝑑  (𝑏  𝑐  𝑑 ) = 0
În expresia logică toate variabilele apar în pereche şi se aplică regula 𝑥  𝑥 = 0.
Dacă însă în cuvântul extins un bit este eronat, atunci codul de eroare este diferit de zero. Să
verificăm acest rezultat pentru un cuvânt în care bitul 𝑎 este eronat. Putem scrie aşadar
𝑎̃ = 𝑎̅ = 𝑎  1, 𝑏̃ = 𝑏, 𝑐̃ = 𝑐, . .. , 𝑟̃ = 𝑟.
Pentru biţii de control sunt valabile relaţiile:

𝑢2 = 𝑏̃  𝑐̃  𝑑̃  𝑝̃ = 𝑏  𝑐  𝑑  𝑝 = 𝑏  𝑐  𝑑  (𝑏  𝑐  𝑑 ) = 0.

𝑢1 = 𝑎̃  𝑐̃  𝑑̃  𝑞̃ = (𝑎  1) 𝑐  𝑑  𝑞 = (𝑎  1) 𝑐  𝑑  (𝑎  𝑐  𝑑 ) = 1.

𝑢0 = 𝑎̃  𝑏̃  𝑑̃  𝑟̃ = (𝑎  1) 𝑏  𝑑  𝑟 = (𝑎  1) 𝑏  𝑑  (𝑎  𝑏  𝑑 ) = 1.

3
Se observă că bitul de 1 folosit la modelarea erorii singulare se reflectă în bitul de eroare rezultat.
În tabelul următor se prezintă valoarea 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului pentru toate erorile singulare.

Tab. 3 Valoarea 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului pentru erori singulare

Bit eronat 𝑝̃ 𝑞̃ 𝑟̃ 𝑎̃ 𝑏̃ 𝑐̃ 𝑑̃
𝑢2 1 0 0 0 1 1 1
𝑢1 0 1 0 1 0 1 1
𝑢0 0 0 1 1 1 0 1
Cod în zecimal 4 2 1 3 5 6 7

Aşa cum rezultă din tabel, pentru toate erorile singulare codurile rezultate sunt distincte. Prin
urmare, bitul eronat poate fi identificat pe baza acestui cod şi apoi corectat prin inversare. Logica
combinaţională de decodare, control şi corecţie se prezintă în figura următoare.

~
d
~ ~
p u2 7 ~
a c
D
~ 6 ~ Date
E
b ~ b către
q u1 C 5 μP
O
~ 4 ~
c D a
O 3
~
r u0
R 2
~ 1
d No error
Syndrome 0

Fig. 3 - Logica de control şi corecţie la codarea SEC_SED.

Concluzionând, dacă la citire se regăsesc toţi biţii de date şi de control salvaţi anterior la scriere,
codul de eroare va cuprinde numai biţi de zero. Când cuvântul are unul sau doi biţi schimbaţi codul
de eroare este diferit de zero. În cazul unei erori singulare, pe baza codului generat, bitul schimbat
este identificat şi apoi corectat prin inversare. Se poate însă remarca, de exemplu, că o combinaţie
1,1,1 în 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒 (codul 7) apare atunci când bitul 𝑑̃ este schimbat, dar şi când biţii 𝑎̃ şi 𝑝̃ sunt
schimbaţi. Ca urmare, dacă în cuvântul extins apar două erori circuitul de corecţie nu mai
funcţionează bine. Când probabilitatea de apariţie a două erori nu poate fi neglijată, se poate
renunţa la facilitatea de corectare a erorilor şi structura de codare poate fi folosită pentru
detectarea uneia sau a două erori în cuvântul extins (structura de tip DED : 𝑑𝑜𝑢𝑏𝑙𝑒 −
𝑒𝑟𝑟𝑜𝑟 𝑑𝑒𝑡𝑒𝑐𝑡𝑖𝑛𝑔). La o valoare diferită de zero a 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului se generează un semnal de eroare
(mai precis, o întrerupere) privind cuvântul citit din memorie. Această tehnică de codare are însă
mai mult o importanţă teoretică.

Structura circuitelor de control la codarea SEC_DED


I. Logica de codare
Biţii de control asociaţi biţilor de date se generează după următoarele relaţii:
𝑝 = 𝑏  𝑐  𝑑, 𝑞 = 𝑎  𝑐  𝑑, 𝑟 = 𝑎  𝑏  𝑑, 𝑠 =𝑎𝑏𝑐

4
Codarea SEC_DED este o extensie a codării SEC_SED prin adăugarea unui bit de paritate (𝑠). Într-
adevăr, pentru bitul suplimentar de control este valabilă relaţia
𝑠 = 𝑎  𝑏  𝑐  𝑑  𝑝  𝑞  𝑟 = 𝑎  𝑏  𝑐  𝑑  (𝑏  𝑐  𝑑)  (𝑎  𝑐  𝑑)  (𝑎  𝑏  𝑑)
=𝑎𝑏𝑐.
Evident, bitul de control 𝑠 se generează cum este mai uşor. Cum nu toţi biţii din cuvântul extins sunt
independenţi a rezultat o relaţie de calcul mai simplă. Logica combinaţională de codare pentru
structura SEC_DED se prezintă în figura următoare.

a p = bcd

b
Cuvânt de date
depus pe q = acd
magistrală de µP
c
r = abd
d

s = abc

Fig. 4 – Logica de codare la varianta SEC_DED.

În Tab. 4 se prezintă mulţimea cuvintelor extinse care se formează. Se observă că între biţii de
date 𝑎, 𝑏, 𝑐, 𝑑 şi biţii de control 𝑝, 𝑞, 𝑟, 𝑠 astfel formaţi există o corespondenţă biunivocă.

Tab. 4 – Mulţimea cuvintelor valide la codarea SEC_DED

𝑎 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
𝑏 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
𝑐 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
𝑑 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
𝑝 0 1 1 0 1 0 0 1 0 1 1 0 1 0 0 1
𝑞 0 1 1 0 0 1 1 0 1 0 0 1 1 0 0 1
𝑟 0 1 0 1 1 0 1 0 1 0 1 0 0 1 0 1
𝑠 0 0 1 1 1 1 0 0 1 1 0 0 0 0 1 1
𝐶𝑜𝑑 𝑑𝑒 𝑐𝑜𝑛𝑡𝑟𝑜𝑙 0 E D 3 B 5 6 8 7 9 A 4 C 2 1 F

La varianta SEC_DED distanţa de cod în sens Hamming este 4. Să facem o verificare intuitivă
aplicând acelaşi raţionament ca la SEC_SED. Cum primul cuvânt conţine numai biţi de 0, celelalte
cuvinte trebuie să aibă cel puţin 4 biţi de 1. Similar, cum ultimul cuvânt conţine numai biţi de 1,
celelalte cuvinte trebuie să conţină cel puţin 4 biţi de 0. Prin urmare, cu excepţia primei şi ultimei
coloane, toate celelalte combinaţii trebuie să aibă 4 biţi de 0 şi 4 biţi de 1, ceea ce se verifică uşor.

5
II. Logica de decodare

Biţii de control se generează după următoarele relaţii:

𝑢3 = 𝑎̃  𝑏̃  𝑐̃  𝑠̃ , 𝑢2 = 𝑏̃  𝑐̃  𝑑̃  𝑝̃, 𝑢1 = 𝑎̃  𝑐̃ 𝑑̃  𝑞̃, 𝑢0 = 𝑎̃  𝑏̃  𝑑̃  𝑟̃


Când cuvântul citit din memorie este fără eroare atunci toţi biţii de control sunt 0, pentru că în
expresii fiecare variabilă logică intervine de două ori. Dacă în cuvânt, unul, doi sau chiar trei biţi sunt
modificaţi atunci codul de eroare este diferit de zero. Să exemplificăm codul de eroare care rezultă
în cazul unui cuvânt în care biţii 𝑎̃ şi 𝑏̃ sunt eronaţi. Pentru acest cuvânt modificat sunt valabile
relaţiile:

𝑎̃ = 𝑎̅ = 𝑎  1, 𝑏̃ = 𝑏̅ = 𝑏  1, 𝑐̃ = 𝑐, . . . , 𝑟̃ = 𝑟, 𝑠̃ = 𝑠.
Rezultă următorii biţi de control:

𝑢3 = 𝑎̃  𝑏̃  𝑐̃  𝑠̃ = 𝑎  1 𝑏  1  𝑐  𝑠 = 𝑎  1 𝑏  1  𝑐  (𝑎  𝑏  𝑐 ) = 0

𝑢2 = 𝑏̃  𝑐̃  𝑑̃  𝑝̃ = 𝑏  1  𝑐  𝑑  𝑝 = 𝑏  1  𝑐  𝑑  (𝑏  𝑐  𝑑 ) = 1.

𝑢1 = 𝑎̃  𝑐̃  𝑑̃  𝑞̃ = 𝑎  1 𝑐  𝑑  𝑞 = 𝑎  1 𝑐  𝑑  (𝑎  𝑐  𝑑 ) = 1.

𝑢0 = 𝑎̃  𝑏̃  𝑑̃  𝑟̃ = 𝑎  1 𝑏  1  𝑑  𝑟 = 𝑎  1 𝑏  1  𝑑  (𝑎  𝑏  𝑑) = 0.

Se poate observa faptul că în orice relaţie de calcul a unui bit de control, toate variabilele logice
apar în pereche şi se anulează reciproc. Prin urmare, valoarea finală va fi dată de biţii de 1 folosiţi la
modelarea erorii. În consecinţă, la un defect multiplu, valoarea 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului se obţine aplicând
operatorul XOR asupra codurilor de la erorile singulare ce compun eroarea multiplă. Aşadar, codul
de eroare poate fi determinat mai uşor, fără să se evalueze explicit relaţiile care intervin. În Tab. 5
se prezintă valoarea 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului atunci când în cuvântul citit unul sau doi biţi sunt schimbaţi.

Tab. 5 – Valoarea 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului la codarea SEC_DED pentru unul sau doi biţi eronaţi

Eroarea Erori singulare Erori duble (𝐶82 = 28 de combinaţii)


analizată 𝑠̃ 𝑝̃ 𝑞̃ 𝑟̃ 𝑑̃ 𝑎̃ 𝑏̃ 𝑐̃ 𝑎̃, 𝑏̃ 𝑎̃, 𝑐̃ 𝑎̃, 𝑑̃ 𝑏̃, 𝑐̃ 𝑏̃, 𝑑̃ . 𝑞̃, 𝑟̃
𝑢3 1 0 0 0 0 1 1 1 0 0 1 0 1 . 0
𝑢2 0 1 0 0 1 0 1 1 1 1 1 0 0 . 0
𝑢1 0 0 1 0 1 1 0 1 1 0 0 1 1 . 1
𝑢0 0 0 0 1 1 1 1 0 0 1 0 1 0 . 1
Comentariu Număr impar de biţi de 1 Număr par de biţi de 1

Se evidenţiază în tabel că pe baza parităţii codului de eroare se pot disocia erorile singulare de
cele duble (în acest scop s-a introdus bitul de control suplimentar 𝑠). Logica de decodare, control şi
corecţie este prezentată în Fig. 5.
Semnificaţia semnalelor de control 𝑆𝐶1 şi 𝑆𝐶2 este următoarea:
• 𝑆𝐶2 = 0, (𝑆𝐶1 = 0) – Nu există erori în cuvântul extins;
• 𝑆𝐶2 = 1, 𝑆𝐶1 = 1 – O eroare singulară a fost corectată, datele sunt valide;
• 𝑆𝐶2 = 1, 𝑆𝐶1 = 0 – Data citită din memorie este eronată.

6
𝑃𝑟𝑒𝑐𝑖𝑧𝑎𝑟𝑒: O eroare singulară la biţii de date poate fi identificată ca şi la SEC_SED doar pe baza
biţilor de control 𝑢2 , 𝑢1 , 𝑢0 . Aşadar, logica de corecţie este simplificată fiind aceeaşi ca şi la SEC_SED.

La o eroare dublă se generează o întrerupere: 𝐼𝑛𝑡 = ̅̅̅̅̅


𝑆𝐶1 ∙ 𝑆𝐶2 .

Fig. 5 – Logica de control şi corecţie la implementarea SEC_DED.

Temă pentru acasă: Să se verifice că dacă în cuvântul citit sunt 3 biţi schimbaţi atunci circuitul de
control şi corecţie nu mai funcţionează bine.

Completare la Cursul 5
Să verificăm în continuare că un cod de eroare diferit de zero se obţine şi în cazul oricărei erori triple.
8 ∙7∙ 6
Numărul lor este 𝐶83 = = 56.
2∙ 3

Reamintim că la o eroare multiplă, valoarea 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului se poate obţine aplicând operatorul


XOR asupra codurilor de la erorile singulare ce o compun. Aşadar, valorile 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului pot fi
determinate direct, pe baza codurilor de eroare din Tabelul 5, fără să se evalueze explicit expresiile
care intervin. În funcție de structura erorii multiple putem evidenția 4 cazuri: cei 3 biți eronați sunt
biți de date, toți biții eronați sunt biți de control, 2 biți eronați sunt biți de date și unul este bit de
control, 2 biți eronați sunt biți de control și unul este bit de date. Să le analizăm pe rînd.
➢ Trei biți de date eronați
În acest caz rezultă întotdeauna un cod de eroare cu trei biți de 0 (pe poziția valorilor de 0 de la
codurile singulare) și un bit de 1.
➢ Trei biți de control eronați
În acest caz rezultă întotdeauna un cod de eroare cu trei biți de 1 (pe poziția valorilor de 1 de la
codurile singulare) și un bit de 0.
➢ Doi biți de date și un bit de control eronați
De la cei doi biți de date eronați rezultă întotdeauna un cod de eroare cu doi biți de 1 și doi biți
de 0. Ca urmare a faptului că şi un bit de control este eronat se poate întâmpla ca la generarea
𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului unul din cei doi biți de 1 să fie mascat, dar nu amândoi.

7
➢ Doi biți de control și un bit de date eronați
De la cei doi biți de control eronați rezultă întotdeauna un cod de eroare cu doi biți de 1 și doi
biți de 0, în timp ce codul de eroare pentru bitul de date modificat cuprinde trei biți de 1. Ca
urmare, la generarea 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului, biții de 1 care modelează eroarea se pot masca parțial dar
nu în întregime.
În concluzie, pentru orice eroare triplă rezultă un 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒 diferit de zero, ceea ce înseamnă
că eroarea este detectabilă. Pot rezulta însă cuvinte de eroare cu un număr impar de biţi de 1 ceea
ce face ca circuitul de corecţie să considere că ar fi o eroare singulară şi să inverseze în mod greşit
un bit corect. Ca urmare, pentru unele erori triple circuitul de coreţie funcţionează greşit. De
exemplu, dacă biţii 𝑎̃, 𝑠̃ şi 𝑝̃ ar fi modificaţi atunci ar rezulta codul 7 şi circuitul de corecţie ar inversa
în mod greşit bitul 𝑑̃.
Ca o concluzie, codurile SEC_DED şi TED ( 𝑡𝑟𝑖𝑝𝑙𝑒 − 𝑒𝑟𝑟𝑜𝑟 𝑑𝑒𝑡𝑒𝑐𝑡𝑖𝑛𝑔 ) sunt identice doar că
valoarea syndrome-ului este interpretată diferit în cele două cazuri.
De remarcat că la această codare o eroare multiplă cu 4 biţi eronaţi ar putea să nu fie detectată.
De exemplu, atunci când biţii 𝑎̃, 𝑏̃, 𝑝̃ şi 𝑞̃ sunt eronaţi codul de eroare rezultat este zero.

8
Sisteme de timp real

Cursul 6 – Specificarea şi proprietăţile codurilor de control

Elemente teoretice de bază privind tehnica codării

Mai întâi câteva notaţii :


𝐷 – numărul erorilor detectabile în cuvântul verificat ;
𝐶 – numărul erorilor ce pot fi corecte automat pe baza informaţiilor suplimentare de control ;
𝑑 – distanţa de cod în sens Hamming care reprezintă numărul minim de biţi prin care două
cuvinte valide diferă între ele.
Cunoaştem că circuitul de control verifică cuvântul citit pentru detectarea eventualelor erori şi
atunci când codarea o permite anumite erori sunt şi corectate. Pentru ca o eroare să poată fi
detectată automat cuvântul rezultat nu trebuie să mai fie unul valid. Sub aspectul capacităţii de
detectare, un cod de control este cu atât mai puternic cu cât ponderea cuvintelor valide din totalul
combinaţiilor posibile este mai redusă. De exemplu, la codul de paritate ce permite detectarea
erorilor singulare, ponderea cuvintelor valide din totalul combinaţiilor posibile este de 50%. La
codarea SEC_SED sau DED, care acoperă atât erorile singulare cât şi pe cele duble, pentru cuvinte
cu 4 biţi de date, ponderea cuvintelor valide este de 24 ⁄27 ∙ 100 = 12,5%. La codarea SEC_DED
sau TED, care asigură detectarea oricărei erori singulare, duble sau triple, pentru cuvinte cu 4 biţi
de date, ponderea cuvintelor valide este de 24 ⁄28 ∙ 100 = 6,25%.
➢ Pentru detectarea a 𝐷 erori în cuvântul recepţionat, codul folosit trebuie să îndeplinească
condiţia :
𝑑 ≥ 𝐷 + 1. (1)
Explicaţia este următoarea : O eroare singulară duce la formarea unui cuvânt modificat la o
distanţă Hamming 1 de cel iniţial. Dacă pentru codul folosit distanţa Hamming ar fi tot 1, atunci
cuvântul afectat de eroare ar putea fi unul valid. Prin urmare, pentru detectarea tuturor erorilor
singulare se impune ca distanţa de cod 𝑑 să fie cel puţin 2. După un raţionament similar, se
deduce că pentru detectarea erorilor duble este nevoie ca 𝑑 ≥ 3 ş.a.m.d.
• Condiţia ca un cod să permită corectarea automată a 𝐶 erori în cuvântul verificat trebuie să
îndeplinească condiţia :
𝑑 ≥ 2𝐶 + 1. (2)

Figurile următoare (6, 7 şi 8) ilustrează necesitatea îndeplinirii acestei condiţii. Cu 𝑤1 şi 𝑤2 sunt


notate două cuvinte valide.

Cuvânt cu un bit eronat


eereronateronat
𝑤1 𝑤2

𝑑=2

Fig. 6 – Eroare singulară necorectabilă

1
Cuvântul 𝑤1 cu un bit eronat
eereronateronat
𝑤1 𝑤2

𝑑=3

Fig. 7 – Eroare singulară corectabilă.

Cuvântul 𝑤1 cu C erori
𝑤1 𝑤2
C 𝐶 + 1

𝑑 = 2𝐶 + 1

Fig. 8 – Eroare multiplă corectabilă.

• Condiţia ca un cod să permită detectarea a 𝐷 erori şi corectarea automată a 𝐶 erori este :


𝑑 ≥ 𝐶 + 𝐷 + 1. (3)

𝐽𝑢𝑠𝑡𝑖𝑓𝑖𝑐𝑎𝑟𝑒 : Întrucât 𝐷 ≥ 𝐶 rezultă că sunt îndeplinite condiţiile (1) şi (2) menţionate anterior.
Cele mai folosite coduri sunt:
• Codul de paritate: 𝑑 = 2 , 𝐶 = 0, 𝐷 = 1;
• Codul SEC_SED: 𝑑 =3, 𝐶 = 1, 𝐷 = 1;
• Codul DED : 𝑑 =3, 𝐶 = 0, 𝐷 = 2;
• Codul SEC_DED: 𝑑 =4, 𝐶 = 1, 𝐷 = 2;
• Codul TED: 𝑑 =4, 𝐶 = 0, 𝐷 = 3.

Relaţiile (1) – (3) evidenţiază importanţa conceptului de distanţă de cod. Pentru a înţelege mai
bine acest concept şi proprietăţile asociate să analizăm în continuare codul de paritate pentru
cuvinte cu 2 biţi de date.
Fie un cuvânt format din doi biți de date 𝑎 și 𝑏 și un bit de paritate 𝑝 = 𝑎  𝑏. Să analizăm mai
întâi combinațiile valide pentru acest cuvânt extins. Bitul 𝑎 se consideră cel mai semnificativ.

Tabelul 6 – Cuvintele valide la codul de paritate studiat

𝑎 0 0 1 1
𝑏 0 1 0 1
𝑝 0 1 1 0
(în octal) 0 3 5 6

Figura următoare (Fig. 9) evidenţiază efectul erorilor singulare asupra acestor cuvinte valide. Din
figură rezultă faptul că orice cuvânt afectat de o eroare singulară nu unul nevalid. Codul de paritate
permite așadar detectarea tuturor erorilor singulare. Totodată, figura arată că orice cuvânt nevalid
poate proveni de la 3 cuvinte valide și prin urmare cauza erorii nu poate fi identificată. Așadar,
erorile detectate nu pot fi și corectate.

2
cuvinte valide cuvinte nevalide
0 1

3 2

5
4

6 7

Fig. 9 - Efectul erorilor singulare

Următoarea figură evidențiază distanța Hamming dintre cuvinte. Se verifică uşor că distanţă de
cod în acest caz este 2.

Fig. 10 – Distanţa Hamming între cuvinte la codul de paritate.

Ambele figuri arată că mulţimea cuvintelor valide are o pondere de 50 % în mulțimea


combinațiilor posibile.
Determinarea distanţei de cod pe baza definiţiei este însă foarte dificilă când 𝑚 are valori mari
2𝑚 (2𝑚 −1)
datorită numărului enorm de comparaţii ce trebuie efectuate (𝐶22𝑚 = 2
 22𝑚−1 ). De
exemplu, pentru 𝑚 = 16 numărul de verificări este  231 > 2 ∙ 109 . Câteva elemente de algebră
lineară simplifică această problemă.
Fie 𝑉 mulţimea cuvintelor valide pentru codul folosit. Cardinalul acestei mulţimi este fireşte 2𝑚 .
Pentru un element 𝑣 ∈ 𝑉, se defineşte ponderea 𝑝(𝑣) ca fiind numărul biţilor de 1 din cuvânt.
Astfel, pentru două cuvinte oarecare 𝑢, 𝑣 ∈ 𝑉, 𝑢 ≠ 𝑣, distanţa Hamming dintre aceste două cuvinte
se poate exprima cu relaţia:
𝑑(𝑢, 𝑣) = 𝑝(𝑢  𝑣) (4)

3
Dar, conform unui rezultat remarcabil de algebră lineară, 𝑉 este o mulţime închisă în raport cu
operatorul sau-exclusiv (). Asta înseamnă că pentru oricare două cuvinte 𝑢, 𝑣 ∈ 𝑉, 𝑢 ≠ 𝑣 , şi
cuvântul rezultat 𝑢  𝑣 ∈ 𝑉. Pe baza acestor elemente, distanţa de cod se exprimă cu relaţia:
𝑑 = 𝑚𝑖𝑛 {𝑝(𝑣), 𝑣 ∈ 𝑉 − 𝑧𝑒𝑟𝑜} (5)
Astfel, se verifică uşor pe mulţimea 𝑉 că la codarea SEC_SED 𝑑 = 3, iar la codarea SEC_DED 𝑑 = 4.
Să analizăm mai în detaliu această proprietate deosebită a mulţimii cuvintelor valide. O ilustrare
grafică a acestei preoprietăţi se prezintă în figura următoare.

Mulţimea cuvintelor valide (𝑉)

𝑢 𝑣 𝑥
Cuvânt
de ⨁
date


Cuvânt
de ⨁
control

Fig. 11 - Proprietatea mulţimii 𝑉 de a fi o mulţime închisă în raport cu operatorul .

Cuvintele de date acoperă toate combinaţiile posibile, de la cea cu cea cu toţi biţii de 0 la cea
cu toţi biţii de 1. Prin urmare, aplicând operatorul  asupra a două cuvinte de date rezultă tot un
cuvânt valid. Problema se reduce la verificarea codului de control. Să considerăm două cuvinte
valide oarecare 𝑢 şi 𝑣 şi cuvântul rezultat prin aplicarea operatorului , 𝑥 = 𝑢  𝑣. Partea de date
a cuvântului nu poate fi decât o combinaţie validă. Aşa cum este ilustrat în figură, trebuie să
verificăm că partea de control a cuvântului 𝑥, rezultată din aplicarea operatorul  asupra biţilor de
control de pe aceeaşi poziţie din cuvintele iniţiale 𝑢 şi 𝑣, se obţine şi atunci când se aplică regula de
codare asupra biţilor de date din cuvântul 𝑥. Ca urmare, cuvântul extins 𝑥 este tot un cuvânt valid.
Să exemplificăm acest lucru pentru primul bit de control de la o codare de tip SEC_SED
considerând cuvinte de date de 4 biţi. Cele două cuvinte iniţiale, 𝑢 şi 𝑣, sunt de următoarea formă:
𝑢 = (𝑑1𝑢 , 𝑑2𝑢 , 𝑑3𝑢 , 𝑑4𝑢 , 𝑐1𝑢 , 𝑐2𝑢 , 𝑐3𝑢 ) şi 𝑣 = (𝑑1𝑣 , 𝑑2𝑣 , 𝑑3𝑣 , 𝑑4𝑣 , 𝑐1𝑣 , 𝑐2𝑣 , 𝑐3𝑣 )
Cuvântul rezultat aplicând operatorul  este
𝑥 = (𝑑1𝑥 , 𝑑2𝑥 , 𝑑3𝑥 , 𝑑4𝑥 , 𝑐1𝑥 , 𝑐2𝑥 , 𝑐3𝑥 ), în care 𝑑1𝑥 = 𝑑1𝑢  𝑑1𝑣 , 𝑑2𝑥 = 𝑑2𝑢  𝑑2𝑣 , … , 𝑐1𝑥 = 𝑐1𝑢  𝑐1𝑣 , …
Cum 𝑐1𝑢 = 𝑑2𝑢  𝑑3𝑢  𝑑4𝑢 şi 𝑐1𝑣 = 𝑑2𝑣  𝑑3𝑣  𝑑4𝑣 rezultă că
𝑐1𝑥 = 𝑐1𝑢  𝑐1𝑣 = 𝑑2𝑢  𝑑3𝑢  𝑑4𝑢  𝑑2𝑣  𝑑3𝑣  𝑑4𝑣 .
Să verificăm că aceeaşi valoare se obţine pentru 𝑐1𝑥 dacă se aplică regula de codare pe biţii de date.
𝑐1𝑥 = 𝑑2𝑥  𝑑3𝑥  𝑑4𝑥 = (𝑑2𝑢  𝑑2𝑣 )  (𝑑3𝑢  𝑑3𝑣 )  (𝑑4𝑢  𝑑4𝑣 ).
Cum nu contează ordinea în care se aplică operatorul logic, rezultă aceeaşi expresie
𝑐1𝑥 = 𝑑2𝑢  𝑑3𝑢  𝑑4𝑢  𝑑2𝑣  𝑑3𝑣  𝑑4𝑣 .

4
Specificarea unui cod

Modelul matematic cel mai avantajos în specificarea şi studiul codurilor lineare este cel
matriceal. Astfel, reprezentarea unui cod linear se face sub forma unei matrice de generare 𝐺 care
conţine toţi vectorii linear independenţi ai codului, cu excepţia codului nul (baza spaţiului vectorial).
Matricea 𝐺 are 𝑚 linii şi 𝑛 = 𝑚 + 𝑘 coloane şi este de forma
𝐺𝑚×𝑛 = [𝐼𝑚  𝑄𝑚×𝑘 ],
în care 𝐼𝑚 este matricea unitate, ca bază pentru toate cuvintele de date, iar 𝑄𝑚×𝑘 este matricea
codurilor suplimentare de control.
Prin combinaţii lineare realizate între liniile acestei matrice se obţin toate cuvintele valide pentru
codul respectiv, mai puţin codul nul. De exemplu, pentru codurile analizate, matricea 𝑄 este de
următoare forma :
a) SEC_SED, 𝑚 = 4, 𝑘 = 3
0 1 1
1 0 1
𝑄4×3 =[ ]
1 1 0
1 1 1

b) SEC_DED, 𝑚 = 4, 𝑘 = 4
0 1 1 1
1 0 1 1
𝑄4×4 =[ ]
1 1 0 1
1 1 1 0
Submatricea 𝑄 din matricea de generare descrie structura logicii de codare. Structura logicii de
decodare este descrisă printr-o matrice de control a parităţii (engl. 𝑝𝑎𝑟𝑖𝑡𝑦 − 𝑐ℎ𝑒𝑐𝑘 𝑚𝑎𝑡𝑟𝑖𝑥) de
𝑇
forma 𝐻 = [𝐼𝑘 𝑄𝑚×𝑘 ] , care evidenţiază biţii din cuvântul extins care intervin la formarea
𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului. Pentru codurile analizate, matricea 𝐻 de generare a 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului este :

a) SEC_SED, 𝑚 = 4, 𝑘 = 3
1 0 0 0 1 1 1
𝐻 = [0 1 0 1 0 1 1]
0 0 1 1 1 0 1

b) SEC_DED, 𝑚 = 4, 𝑘 = 4
1 0 0 0 0 1 1 1
0 1 0 0 1 0 1 1
𝐻=[ ]
0 0 1 0 1 1 0 1
0 0 0 1 1 1 1 0

Dacă cuvântul citit din memorie este [𝑐1 𝑐2 … 𝑐𝑘 𝑑1 𝑑2 … 𝑑𝑚 ] atunci codul de eroare sau
𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ul (𝑆) de lungime 𝑘 se obţine cu relaţia :

𝑆𝑘×1 = ⊕ (𝐻𝑘×(𝑘+𝑚) × [𝑐1 𝑐2 … 𝑐𝑘 𝑑1 𝑑2 … 𝑑𝑚 ]𝑇 ). (6)

5
Pentru o soluţie optimală, la codarea SEC_DED, matricea 𝐻 de generare a 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒 -ului
trebuie să îndeplinească următoarele condiţii :
• Numărul de biţi de 1 de pe fiecare coloană trebuie să fie impar – condiţie care derivă din
principiul codării;
• Numărul total de biţi de 1 din matrice trebuie să fie minim – condiţie ce urmăreşte reducerea
complexităţii logicii de control;
• Numărul de biţi de 1 de pe oricare două linii trebuie să fie acelaşi sau, dacă nu este posibil, să
fie cât mai apropiat de o valoare medie (valoare dată de raportul dintre numărul biţilor de 1 din
matrice şi numărul de linii) – condiţie ce urmăreşte ca timpul de propagare prin logica de
control să fie cât mai mic.
De exemplu, pentru o memorie cu lungimea cuvântului de date de 16 biţi, o matrice optimală de
control a parităţii la codarea SEC_DED este următoarea :

1 0 0 0 0 0 1 0 0 1 1 0 0 1 0 0 1 1 1 1 0 0
0 1 0 0 0 0 0 0 1 1 1 1 1 0 1 0 0 0 1 0 1 0

0 0 1 0 0 0 1 1 1 0 1 1 1 0 0 1 1 0 0 0 0 0
H = 
0 0 0 1 0 0 1 1 1 0 0 0 0 1 1 1 0 1 0 0 0 1
0 0 0 0 1 0 0 0 0 1 0 0 1 1 1 1 0 0 0 1 1 1
 
0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 0 1 1 1 1 1 1

Fig. 12 – Matricea de generare a 𝑠𝑦𝑛𝑑𝑟𝑜𝑚𝑒-ului în varianta SEC_DED (𝑚 = 16, 𝑘 = 6).

Pe această matrice, se verifică uşor îndeplinirea condiţiilor menţionate anterior.

Temă pentru acasă


Să se evalueze complexitatea logicii adiţionale (exprimată în porţi echivalente) la o codare de tip
SEC_DED şi creşterea timpului de acces la memorie, ca urmare a interpunerii între magistrala de
date şi circuitele de memorie a structurilor combinaţionale de codare, control şi corecţie. Pentru
lungimea cuvântului de date se consideră două cazuri, când 𝑚 = 4 şi când 𝑚 = 16. Se ia ca
referinţă complexitatea unei porţi logice cu două intrări (𝒞 = 1 𝑝𝑒 ) şi timpul de propagare printr-o
astfel de poartă logică, notat cu ∆.
Precizare: Pentru logica de codare şi cea de control se folosesc porţi XOR cu 2 intrări ca celule de
bază, pentru care 𝒞 = 2,5 𝑝𝑒 , iar 𝑇𝑝 = 2,5 ∆.

Observaţii finale
➢ Implementarea codurilor de control asigură o creştere semnificativă a fiabilităţii şi securităţii
părţii de memorie RAM. Această creştere este cu atât mai ridicată cu cât fiabilitatea circuitelor
componente este mai mare.

6
➢ Varianta SEC_SED conduce la o creştere mai mare a fiabilităţii faţă de varianta SEC_DED. Şi în
ceea ce priveşte complexitatea sau timpul de acces la memorie varianta SEC_SED este de
preferat.

➢ Varianta SEC_DED asigură în schimb o securitate mult mai ridicată. Aşadar, această variantă se
adoptă atunci când condiţia privind securitatea sistemului este dominantă.

➢ Cu privire la erorile ce pot apărea la nivelul logicii de codare, se remarcă faptul că dacă biţii de
control se generează în mod independent, atunci o eroare singulară în logica de codare
afectează un singur bit din cuvântul extins şi, ca urmare, acesta este mascat de logica de
control şi corecţie.
➢ O eroare în cuvântul citit din memorie poate avea mai multe cauze, şi anume:
• Defectarea unui circuit de memorie sau activarea unui defect de memorie greu de detectat
care a trecut de testele aplicate; dacă structura de memorie este formată din circuite
orientate pe bit atunci aceste defecte conduc la erori singulare şi sunt corectate automat în
cazul memoriei cu coduri de control.
• Apariţia unor erori tranzitorii ca urmare a unor perturbaţii severe cum ar fi impactul cu
particule grele. Structura redundantă cu coduri de control constituie o soluţie foarte
eficientă de protejare împotriva acestor tipuri de erori.

7
Sisteme de timp real

Cursul 7 – Structură de memori RAM cu redundanţă activă

În acest curs vom analiza o structură de memorie RAM redundantă, reconfigurabilă care să
permită testarea cvasipermanentă a circuitelor de memorie şi, în caz de defectare a unui circuit,
înlocuirea circuitului defect cu altul de rezervă. Aşadar, vom analiza o structură de memorie RAM
cu redundanţă activă sau de comutaţie.
Testarea memoriei RAM poate fi realizată prin programe de test, care să fie executate de
procesor în perioadele de pauză, sau de relaxare în funcţionarea sistemului. În engleză, această
tehnică este numită 𝑛𝑜𝑛 − 𝑐𝑜𝑛𝑐𝑢𝑟𝑟𝑒𝑛𝑡 𝑜𝑛𝑙𝑖𝑛𝑒 𝑡𝑒𝑠𝑡𝑖𝑛𝑔 şi urmăreşte detectarea cât mai rapidă a
defectelor permanente de memorie. În aplicaţiile critice, această verificare este încă insuficientă,
impunându-se o testare cvasipermanentă a memoriei, în timpul funcţionării normale – tehnică
numită 𝑐𝑜𝑛𝑐𝑢𝑟𝑟𝑒𝑛𝑡 𝑜𝑛𝑙𝑖𝑛𝑒 𝑡𝑒𝑠𝑡𝑖𝑛𝑔. O problemă a testării 𝑜𝑛𝑙𝑖𝑛𝑒 a memoriei RAM este aceea că
prin testare conţinutul memoriei se pierde. De aceea, testarea 𝑜𝑛𝑙𝑖𝑛𝑒 necesită circuite suplimentare
pentru salvarea datelor pe durata procesului de testare.

1. Prezentarea structurii redundante studiate

În cele ce urmează va fi analizat un sistem de memorie cu structură redundantă ce permite


testarea secvenţială a modulelor de memorie în paralel cu funcţionarea normală. Sistemul are o
structură reconfigurabilă care asigură înlocuirea unui circuit defect cu altul de rezervă. Vor fi
analizate aici numai aspectele legate de redundanţa dinamică a structurii de memorie, fără să
abordăm problematica propriu-zisă a testării. De aceea se presupune că sistemul de memorie este
compus din circuite autotestabile, cu logică de testare integrată, de tip BIST-RAM (engl. 𝐵𝑢𝑖𝑙𝑡 −
𝐼𝑛 𝑆𝑒𝑙𝑓 − 𝑇𝑒𝑠𝑡𝑖𝑛𝑔 𝑅𝐴𝑀 𝑑𝑒𝑣𝑖𝑐𝑒𝑠).
Fie structura de memorie RAM cu redundanţă activă prezentată în Fig. 1. Necesarul de memorie
implică folosirea a 𝑚 circuite de bază. Pe lângă acestea, sistemul mai cuprinde alte 𝑠 circuite
suplimentare. Din cele 𝑚 + 𝑠 circuite de memorie, 𝑚 sunt utilizate efectiv, unul este supus testării
şi celelalte 𝑠 − 1 sunt în 𝑠𝑡𝑎𝑛𝑑 − 𝑏𝑦. Modulele indisponibile, cele defecte şi cel în curs de testare,
sunt marcate cu 1 în registrul de stare 𝑆𝑅. Sistemul funcţionează cu primele 𝑚 module disponibile,
numărate de la stânga la dreapta şi sărind peste cele inoperabile. Atunci când se defectează un
modul de bază este activat un modul de rezervă. Sistemul de memorie poate tolera până la 𝑠 module
defecte. Structura combinaţională de control asigură reconfigurarea sistemului pentru testarea pe
rând a modulelor de memorie.
Circuitele de memorie sunt testate unul câte unul, la un anumit interval de timp 𝑇. Registrul de
stare (𝑆𝑅) este actualizat de către procesor pentru a marca modulul în curs de testare şi modulele
care în urma testării sunt găsite defecte.

1
modul defect modul în curs de testare modul disponibil

registru de
stare (SR) 0 1 ∙∙∙ 1 ∙∙∙ 0 0 ∙∙∙ 0

adrese logice
Structură combinaţională de selecţie şi reconfigurare

A1 ÷ Am S1 S2 Sj Sm Sm+1 Sm+s

decodor M1 M2 ∙∙∙ Mj ∙∙∙ Mm Mm+1 ∙∙∙ Mm+s

date
adrese

Fig. 1 – Structură de memorie RAM cu redundanţă activă.

2. Testarea online a circuitelor din aria de memorie

Fiecare circuit este verificat de două ori într-un ciclu de testare, aria circuitelor de memorie fiind
parcursă mai întâi în ordine descrescătoare, de la dreapta la stânga (+), şi apoi în ordine crescătoare,
de la stânga la dreapta (–). Pentru testarea unui modul 𝑀𝑗 sunt necesare următoarele operaţii :
• Modulul 𝑀𝑗±1 este adus în regim de funcţionare normală (𝑆𝑅𝑗±1 = 0) ;
• Datele din modulul 𝑀𝑗 sunt salvate în modulul 𝑀𝑗±1 ;
• Este lansat procesul de testare pentru modulul 𝑀𝑗 (𝑆𝑅𝑗 = 1).

În Fig. 2 este ilustrat un ciclu de testare a ariei de memorie cu 𝑚 circuite de bază şi unul
suplimentar care asigură posibilitatea testării 𝑜𝑛𝑙𝑖𝑛𝑒. Modulele logice (partiţiile) sunt numerotate
de la 1 la 𝑚. Circuitul în curs de testare este marcat cu *. Funcţionarea normală a sistemului este
întreruptă doar pe durata transferului de date, înaintea testării unui modul. Transferul de date este
însă rapid, mai ales dacă se realizează cu circuite de acces direct la memorie, şi se presupune că
poate fi tolerat în aplicaţia considerată.
Faţă de procedura de testare a circuitelor prin rotaţie, în acest caz, prin alternarea sensului de
parcurgere a ariei de memorie, numărul operaţiilor de transfer pentru salvarea datelor înaintea
testării se reduce la jumătate. Trebuie însă menţionat ca dezavantaj faptul că circuitele de memorie
nu sunt testate la intervale egale de timp. Acest aspect este evidenţiat în Fig. 3, în care se consideră
o arie de memorie cu patru circuite de bază şi unul suplimentar pentru testarea 𝑜𝑛𝑙𝑖𝑛𝑒. Circuitele
de memorie sunt numerotate de la 1 la 5. Pentru fiecare din cele cinci circuite de memorie se indică
perioada dintre două testări consecutive.

2
1 2 3 . 𝑗− 1 𝑗 j+1 . m−1 m *
1 2 3 . j−1 j j+1 . m−1 * m
1 2 3 . j−1 j j+1 . * m−1 m
. . . . . . . . . . .
1 2 3 . j−1 j * . m−2 m−1 m
1 2 3 . j−1 * j . m−2 m−1 m
1 2 3 . * j−1 j . m−2 m−1 m
. . . . . . . . . . .
1 2 * . j−2 j−1 j . m−2 m−1 m
1 * 2 . j−2 j−1 j . m−2 m−1 m

* 1 2 . j−2 j−1 j . m−2 m−1 m


1 * 2 . j−2 j−1 j . m−2 m−1 m
1 2 * . j−2 j−1 j . m−2 m−1 m
. . . . . . . . . . .
1 2 3 . * j−1 j . m−2 m−1 m
1 2 3 . j−1 * j . m−2 m−1 m
1 2 3 . j−1 j * . m−2 m−1 m
. . . . . . . . . . .
1 2 3 . j−1 j j+1 . * m−1 m
1 2 3 . j−1 j j+1 . m−1 * m
1 2 3 . j−1 j j +1 . m−1 m *

Fig. 2 − Un ciclul de testare pentru aria de memorie.

Fig. 3 – Perioada dintre două testări consecutive (m = 4, s = 1).

3
Aşa cum rezultă din figură, pentru un sistem de memorie cu 𝑚 module de bază şi unul
suplimentar, intervalele de timp dintre două testări consecutive sunt :

2𝑚𝑇 pentru modulele 𝑀1 şi 𝑀𝑚+1,


şi respectiv, (1)
𝑚
2(𝑗−1)𝑇 şi 2(𝑚−𝑗 + 1)𝑇, în alternanţă, pentru modulele 𝑀𝑗 şi 𝑀𝑚+2−𝑗 , j = 2, 3, ... [ 2 ] + 1.

3. Sinteza logicii de selecţie şi reconfigurare

Complexitatea logicii de selecţie şi reconfigurare depinde de numărul de circuite suplimentare


𝑠. Să presupunem o structură redundantă cu două circuite suplimentare (𝑠 = 2).
Fie 𝐴𝑖 , 𝑖 = 1, 2, … , 𝑚, adresa logică care indică partiţia accesată la o operaţie de lucru cu
memoria. Evident, adresa logică fiind decodificată, un singur bit de adresă poate avea valoarea 1.
Semnalele pentru selecţia circuitelor de memorie sunt notate cu 𝑆𝑗 , 𝑗 = 1, 2, … , 𝑚 + 2. Activarea
semnalului 𝑆𝑗 se face în funcţie de adresele 𝐴𝑖 , 𝑖 = 1, 2, … , 𝑚, şi de valorile registrului de stare,
𝑆𝑅𝑗 , 𝑗 = 1, 2, … , 𝑚 + 2. Evident, nu poate fi activat un circuit 𝑀𝑗 decât atunci când acesta este
operaţional (𝑆𝑅𝑗 = 0). Mai precis, structura de control trebuie să activeze primul circuit disponibil
când 𝐴1 = 1, al doilea circuit când 𝐴2 = 1, ş.a.m.d., al 𝑚 − lea circuit disponibil când 𝐴𝑚 = 1.
Ţinând cont de acest lucru rezultă că atunci când sunt operaţionale, modulele 𝑀1 , 𝑀2 , … , 𝑀𝑚+2
sunt selectate astfel :
(1) 𝑀1 este selectat numai dacă 𝐴1 = 1;
(2) 𝑀2 este selectat în două situaţii :
• 𝑀1 şi 𝑀2 sunt operaţionale şi 𝐴2 = 1;
• 𝑀1 este neoperaţional şi 𝐴1 = 1.
(3) Un modul 𝑀𝑗 , 𝑗 = 3, 4, … , 𝑚 este selectat în următoarele trei situaţii :
• Modulele 𝑀1 ÷ 𝑀𝑗 sunt operaţionale şi 𝐴𝑗 = 1;
• Unul din modulele 𝑀1 ÷ 𝑀𝑗−1 este neoperaţional şi 𝐴𝑗−1 = 1;
• Două din modulele 𝑀1 ÷ 𝑀𝑗−1 sunt neoperaţionale şi 𝐴𝑗−2 = 1.

(4) Modulul 𝑀𝑚+1 este selectat în două situaţii :


• Unul din modulele 𝑀1 ÷ 𝑀𝑚 este neoperaţional şi 𝐴𝑚 = 1;
• Două din modulele 𝑀1 ÷ 𝑀𝑚 sunt neoperaţionale şi 𝐴𝑚−1 = 1.
(5) Modulul 𝑀𝑚+2 este selectat numai dacă două din modulele 𝑀1 ÷ 𝑀𝑚+1 sunt neoperaţionale
iar 𝐴𝑚 = 1.
Plecând de la condiţiile (1) – (5) definite anterior, pentru logica combinaţională de selecţie şi
reconfigurare se are în vedere o structură celulară ca cea din Fig. 4, în care blocurile 𝐵𝑆3 ÷ 𝐵𝑆𝑚
sunt identice.

4
Fig. 4 – Structura celulară a logicii de selecţie şi reconfigurare.

Variabilele logice de stare notate cu 𝑥 au următoarea semnificaţie :


• 𝑥1 = 0 – modulul 𝑀1 este operaţional;

• 𝑥22 = 0, 𝑥21 = 0 – modulele 𝑀1 şi 𝑀2 sunt operaţionale;

𝑥22 = 0, 𝑥21 = 1 – unul din module, 𝑀1 sau 𝑀2 , este neoperaţional;

𝑥22 = 1, 𝑥21 = 0 – atât 𝑀1 cât şi 𝑀2 sunt neoperaţionale;


• Pentru j = 3, 4, …, m+2:

𝑥𝑗2 = 0, 𝑥𝑗1 = 0 – toate modulele 𝑀1 ÷ 𝑀𝑗 sunt operaţionale;

𝑥𝑗2 = 0 , 𝑥𝑗1 = 1 – unul din modulele 𝑀1 ÷ 𝑀𝑗 este neoperaţional;

𝑥𝑗2 = 1, 𝑥𝑗1 = 0 – două din modulele 𝑀1 ÷ 𝑀𝑗 sunt neoperaţionale;

𝑥𝑗2 = 1, 𝑥𝑗1 = 1 – mai mult de două din modulele 𝑀1 ÷ 𝑀𝑗 sunt neoperaţionale.

1 2
𝑃𝑟𝑒𝑐𝑖𝑧𝑎𝑟𝑒: Variabilele logice 𝑥𝑚+2 şi 𝑥𝑚+2 pot fi folosite pentru testarea funcţionării corecte a
structurii combinaţionale de selecţie şi reconfigurare de către procesor. Valorile acestor variabile
trebuie să fie în concordanţă cu numărul biţilor de 1 din registrul de stare 𝑆𝑅. De asemenea, când
ambele valori sunt 1 se poate genera o întrerupere pentru a semnala faptul că nivelul de redundanţă
a fost depăşit.
Sinteza logicii de selecţie şi reconfigurae se reduce aşadar la sinteza celulelor:
𝐵𝑆1 , 𝐵𝑆2 , 𝐵𝑆𝑗 ( 𝑗 = 3 ÷ 𝑚), 𝐵𝑆𝑚+1 şi 𝐵𝑆𝑚+2 .

Pentru variabilele de selecţie, 𝑆𝑗 (𝑗 = 1 ÷ 𝑚 + 2), rezultă următoarele funcţii logice :

𝑆1 = 𝑆𝑅1 𝐴1 . (2)

𝑆2 = 𝑆𝑅2 (𝐴2 𝑥1 + 𝐴1 𝑥1 ). (3)

2 1 2 1 2 1
𝑆𝑗 = 𝑆𝑅𝑗 (𝐴𝑗 𝑥𝑗−1 𝑥𝑗−1 + 𝐴𝑗−1 𝑥𝑗−1 𝑥𝑗−1 + 𝐴𝑗−2 𝑥𝑗−1 𝑥𝑗−1 ) , ( 𝑗 = 3, 4, . . . , 𝑚) (4)

5
2 1 2 𝑥 1 ).
𝑆𝑚+1 = 𝑆𝑅𝑚+1 (𝐴𝑚 𝑥𝑚 𝑥𝑚 + 𝐴𝑚−1 𝑥𝑚 𝑚 (5)

1 2
𝑆𝑚+2 = 𝑆𝑅𝑚+2 𝐴𝑚 𝑥𝑚+1 𝑥𝑚+1 . (6)

Variabilele logice 𝑥21 , 𝑥22 şi 𝑥𝑗1 , 𝑥𝑗2 ( 𝑗 = 3 ÷ 𝑚 + 2) sunt date de ecuaţiile :

𝑥21 = 𝑥1 𝑆𝑅2 + 𝑥1 𝑆𝑅2 . (7)

𝑥22 = 𝑥1 𝑆𝑅2 . (8)

1 ̅̅̅̅̅ 2 ̅̅̅̅̅
𝑥𝑗1 = 𝑥𝑗−1
2 1
𝑥𝑗−1 2
𝑆𝑅𝑗 + 𝑥𝑗−1 𝑥𝑗−1 𝑆𝑅𝑗 + 𝑥𝑗−1 1
𝑥𝑗−1 2
𝑆𝑅𝑗 + 𝑥𝑗−1 1
𝑥𝑗−1 =

1 2 1 ̅̅̅̅̅ 2 1 1 1 2 2 ̅̅̅̅̅
= 𝑥𝑗−1 𝑆𝑅𝑗 + 𝑥𝑗−1 𝑥𝑗−1 𝑆𝑅𝑗 + 𝑥𝑗−1 𝑥𝑗−1 = 𝑥𝑗−1 𝑆𝑅𝑗 + 𝑥𝑗−1 (𝑥𝑗−1 + 𝑥𝑗−1 𝑆𝑅𝑗 ) =

1
= 𝑥𝑗−1 1
𝑆𝑅𝑗 + 𝑥𝑗−1 2
(𝑥𝑗−1 + ̅̅̅̅̅
𝑆𝑅𝑗 ). (9)

𝑥𝑗2 = 𝑥𝑗−1
2 1
+ 𝑥𝑗−1 2
𝑥𝑗−1 2
𝑆𝑅 = 𝑥𝑗−1 1
+ 𝑥𝑗−1 𝑆𝑅. (10)

Structura celulelor de selecţie va fi analizată mai în detaliu la laborator.

Temă de casă:
Pentru o structură de memorie redundantă cu 4 circuite de bază şi un circuit suplimentar (𝑚 = 4
şi 𝑠 = 1), să se deseneze logica de selecţie şi reconfigurare şi să se evalueze creşterea timpului de
acces la memorie. Se ia ca referinţă timpul de propagare printr-o poartă logică cu 2 intrări (∆).

4. Eficienţa redundanţei

Îmbunătăţirea fiabilităţii memoriei prin adăugarea a 𝑠 circuite de rezervă poate fi exprimată


destul de bine prin raportul 𝑟 dintre probabilitatea de defectare a unui singur modul din cele 𝑚 ce
compun memoria neredundantă şi probabilitatea de defectare a 𝑠 + 1 module din cele 𝑚 + 𝑠 ce
compun memoria redundantă. Acest raport arată de câte ori se reduce riscul de defectare în
varianta redundantă fată de varianta neredundantă.

Fie 𝑅 = 𝑒 −𝜆𝑡 funcţia de fiabilitate a unui singur circuit, adică probabilitatea de funcţionare
corectă a acestuia în intervalul [0, 𝑡]. Probabilitea de defectare este 𝐹 = 1 − 𝑅 = 1 − 𝑒 −𝜆𝑡 . Cu 𝜆
s-a notat rata medie de defectare a unui circuit de memorie.
Relativ la sistemul neredundant, probabilitatea de funcţionare corectă a celor 𝑚 module
componente este 𝑅𝑚 , iar probabilitatea ca unul dintre module să se defecteze este
𝑃1 = 𝑚𝑅 𝑚−1 𝐹. (11)
În ceea ce priveşte sistemul redundant, probabilitatea ca din cele 𝑚 + 𝑠 module 𝑠 + 1 să se
defecteze este
𝑠+1
𝑃𝑠+1 = 𝐶𝑚+𝑠 (1 − 𝑅)𝑠+1 𝑅 𝑚−1. (12)

6
Creşterea fiabilităţii sau scăderea probabilităţii de defectare este dată de elaţia

𝑃 𝑚𝑅 𝑚−1 (1−𝑅) 𝑚
𝑟 = 𝑃 1 = 𝐶 𝑠+1 𝑅𝑚−1 (1−𝑅)𝑠+1 = 𝐶 𝑠+1 (1−𝑅)𝑠 . (13)
𝑠+1 𝑚+𝑠 𝑚+𝑠

Să facem un calcul numeric pentru 𝑚 = 8, 𝑠 = 2, 𝜆 = 10−7 ℎ−1 . Creşterea fiabilităţii memoriei


RAM (sau, altfel spus, scăderea probabilităţii de defectare) prin adăugarea a două circuite de rezervă
este ilustrată în tabelul următor. S-au considerat diferite perioade de timp între 1 şi 10 ani.

Tabelul 1 – Creşterea fiabilităţii memoriei : 𝑚 = 8, 𝑠 = 2, 𝜆 = 10−7 ℎ−1.

Perioada 1 an 2 ani 5 ani 7 ani 10 ani

r 86952 21757 3490 1784 876

Rezultatele numerice evidenţiază faptul că eficienţa redundanţei este cu atât mai mare cu cât
fiabiliatea circuitelor componente (𝑅 în acest caz) este mai ridicată.

7
Sisteme de timp real

Cursul 8

Arii de discuri magnetice tolerante la defecte

Particularităţile lucrului cu discul magnetic

Creşterea rapidă a capacităţii de prelucrare a datelor în sistemele de calcul face ca aplicaţiile să


fie din ce în ce mai complexe. Acestea implică gestionarea unui volum mare de date şi o frecvenţă
crescută a operaţiile de lucru cu discul magnetic. În sistemele de timp real tranzacţionale, care
gestionează baze de date de mari dimensiuni, timpul de răspuns depinde în mare măsură de
performanţele de timp de acces la disc. Dacă relativ la capacitatea de memorare, discurile magnetice
cunosc o evoluţie rapidă, în ceea ce priveşte performanţele dinamice, de care depinde rata de
transfer, evoluţia este mult mai lentă. De exemplu, timpul mediu de poziţionare a ansamblului de
capete (engl. average seek time) s-a redus de la ≈16ms la ≈4ms în circa 25-30 de ani. Aceasta face
ca viteza de creştere a ratei de transfer între memoria internă şi discul magnetic să fie relativ lentă.
Se poate spune că discul magnetic este un punct de ştrangulare a performanţelor de timp de răspuns
în sistemele tranzacţionale. Întrucât adresele de cilindru au un pronunţat caracter aleatoriu, soluţia
clasică de reducere a timpului de acces la disc folosind o memorie cache are o eficienţă scăzută.
Pentru a reduce decalajul dintre viteza de creştere a puterii de prelucrare a procesoarelor (de
aproximativ 25-30% pe an) şi viteza relativ scăzută de creştere a ratei de transfer cu discul magnetic
(de numai 4-5% pe an), se impune lucrul cu mai multe discuri în paralel.
În acelaşi timp, faţă de celelalte elemente ale unui sistem de calcul, discul magnetic are
fiabilitatea cea mai redusă, iar pierderea datelor poate avea consecinţe deosebit de grave. Folosirea
mai multor discuri magnetice, pentru satisfacerea cerinţelor tot mai mari privind capacitatea de
memorare, înrăutăţeşte fiabilitatea sistemului. Timpul mediu de bună funcţionare pentru un sistem
cu mai multe discuri magnetice scade proporţional cu numărul de discuri. În aceste condiţii,
creşterea fiabilităţii sistemului de discuri magnetice nu este posibilă decât prin implementarea unor
tehnici de toleranţă la defecte sau erori. În concluzie, realizarea unui ansamblu de discuri de mare
performanţă urmăreşte, pe de o parte, scăderea timpului mediu de acces şi, pe de altă parte,
asigurarea unui nivel cât mai ridicat de toleranţă la erori.
Soluţia clasică de implementare a toleranţei la erori constă în păstrarea în permanenţă a unei
copii de rezervă folosind un sistem de discuri duale, aşa cum este ilustrat în Fig. 1 (engl. disk-
mirroring). Scrierea se face în paralel pe cele două discuri, iar citirea se poate face de pe oricare din
ele. Pentru a reduce timpul de acces se alege discul care trebuie să facă o cursă mai mică pentru
poziţionarea ansamblului de capete pe cilindrul adresat.
Pentru volume mari de date se formează arii de discuri duale. Dublarea resurselor de memorie,
impusă de toleranţa la erori, conduce la un supracost ridicat, de peste 100%. Acesta este principalul
dezavantaj al arhitecturii duale. În plus, odată cu prima defectare se pierde toleranţa la erori. Pentru
o fiabilitate ridicată trebuie prevăzute şi alte discuri de rezervă care să le înlocuiască la nevoie pe
cele defecte.
1
Fig. 1 – Arhitectura disk–mirroring.

Pentru a depăşi neajunsurilor arhitecturii disk-mirroring s-au realizat arii de discuri tolerante la
defecte care se bazează pe coduri suplimentare de control. Un astfel de sistem este format din mai
multe discuri identice, dispuse ca într-un vector, fiecare disc fiind prevăzut cu canal propriu de acces
la memorie. Discurile folosite nu sunt deosebite din punct de vedere al fiabilităţii, deci mai
rezonabile ca preţ şi eventual cu performanţe dinamice mai bune. Au fost propuse mai multe
arhitecturi de arii de discuri numite RAID (engl. Redundant Array of Independent Disks), dintre care
cea mai folosită este arhitectura RAID 5. Aceasta va fi analizată în detaliu în cele ce urmează.

Arhitectura RAID 5

Ariile de discuri magnetice cu arhitectură RAID 5 (numită şi Rotating Parity Array) se


caracterizează prin faptul că informaţia de paritate este distribuită uniform pe toate discurile ce
compun structura redundantă. Configuraţia RAID 5 tolerează defectarea unui disc din aria cu 𝑁 + 1
discuri, oricare ar fi acesta. La arhitectura RAID 5 se întâlnesc două variante de organizare a datelor
care asigură aceeaşi toleranţă la erori, dar care conduc la performanţe diferite de timp de acces în
funcţie de particularităţile aplicaţiei.

Organizarea datelor – varianta I

Fie un sistem cu arhitectură RAID 5 compus din 𝑁 + 1 discuri identice. Datele dintr-un fişier sunt
dispuse de-a lungul ariei de discuri. Blocurile de date (clusterele) cu acelaşi număr de ordine de pe
cele 𝑁 + 1 discuri formează un grup de paritate şi acesta constituie unitatea elementară de alocare
pentru un fişier. Dintre cele 𝑁 + 1 blocuri de date, 𝑁 conţin date propriu-zise iar unul conţine
informaţie de control (numită de paritate deoarece se obţine aplicând operatorul sau-exclusiv).
Blocurile de paritate sunt dispuse în spirală aşa cum este ilustrat în Fig. 2. Semnificaţia notaţiilor din
figură este următoarea:
𝑗
𝐷𝑖 – blocul de date de pe discul 𝑗 care aparţine grupului de paritate 𝑖.
𝑃𝑖 – blocul de paritate pentru grupul cu numărul de ordine 𝑖.

2
1 2 3 4

𝑃1 𝐷12 𝐷13 𝐷14


𝐷21 𝑃2 𝐷23 𝐷24
𝐷31 𝐷32 𝑃3 𝐷34 ⟵ Grup de paritate

𝐷41 𝐷42 𝐷43 𝑃4


𝑃5 𝐷52 𝐷53 𝐷54
𝐷61 𝑃6 𝐷63 𝐷64
𝐷71 𝐷72 𝑃7 𝐷74
𝐷81 𝐷82 𝐷83 𝑃8

Fig. 2 – Organizarea datelor la arhitectura RAID 5 – varianta I.

Blocul de paritate se construieşte aplicând operatorul XOR asupra datelor utile, astfel că
𝑗
𝑃𝑖 = XOR 𝐷𝑖 , 𝑖 = 1, 2, 3, … ; 𝑗 = 1, 2, ⋯ , 𝑁 + 1. (1)
𝑗≠1+(𝑖−1)%(𝑁+1)

Depunerea datelor în fâşii, de-a lungul ariei de discuri, urmăreşte două obiective, şi anume:
• Transferul datelor în paralel pentru satisfacerea mai rapidă a unei cereri.
• Echilibrarea încărcării discurilor pentru ca frecvenţa neuniformă cu care sunt accesate fişierele
să nu mai afecteze timpul de acces la disc (o soluţie foarte bună din acest punct de vedere).
Legat de transferul datelor în paralel, trebuie însă observat faptul că în acest caz intervin mai
mulţi timpi de poziţionare a braţului şi timpi de rotaţie pentru localizarea începutului de bloc. Acest
efect de întârziere poate domina câştigul de timp de la transferul propriu-zis, aşa se arată în Fig. 3.

1 1 1
tp tr tt
disc 1
2 2 2
tp tr tt
disc 2

timp de transfer ( Ta )

a) datele sunt stocate pe discurile 1 şi 2 şi transferate în paralel.

1 1 1 2
tp tr tt + tt
disc 1
timp de transfer ( Tb )

b) datele ocupă o zonă contiguă pe discul 1.

Fig. 3 – Timpul de transfer a unui bloc de date (𝑇𝑎 > 𝑇𝑏 ).

3
Notaţiile din figură au următoarea semnificaţie:
𝑡𝑝 − timpul de poziţionare a braţului de citire-scriere pe cilindrul solicitat (engl. seek time);
𝑡𝑟 − timpul de rotaţie pentru localizarea începutului de bloc (engl. latency time);
𝑡𝑡 − timpul de transfer propriu-zis.
Mărimrea blocurilor de date implicate în transfer influenţează în mare măsură performanţele
arhitecturii RAID 5, acestea fiind mai bune când blocurile de date sunt mai mari.

Organizarea datelor – varianta II

Analizele efectuate pe sisteme reale arată că în multe sisteme tranzacţionale predomină cererile
de transfer a unor blocuri de date de dimensiuni reduse, de regulă mai mici de 10KB. De exemplu,
în cazul sistemelor tranzacţionale bancare. În astfel de sisteme, la care blocurile de date implicate
în transfer sunt de mici dimensiuni, lucrul în paralel cu mai multe discuri nu conduce la o
îmbunătăţire a performanţelor de timp de acces. De aceea, în multe implementări se renunţă la
memorarea unui fişier de-a lungul ariei de discuri. Se păstrează însă ideea blocurilor de paritate
pentru recuperarea datelor în caz de eroare. Organizarea datelor în această variantă este prezentată
în Fig. 4. Fiecare disc este împărţit în 𝑁 + 1 partiţii, dintre care una este rezervată pentru informaţii
de paritate. 𝑁 blocuri de date provenind de la 𝑁 discuri formează un grup de paritate, iar informaţia
de control este memorată în partiţia de paritate a discului rămas. Blocul de paritate se construieşte
cu relaţia
𝑗
𝑃𝑖 = XOR 𝐷𝑖 , 𝑖 = 1, 2, 3, … ; 𝑗 ia 𝑁 valori distincte din mulțimea {1, 2, …, 𝑁 + 1}. (2)
𝑗

1 2 3 4

𝐷11 𝐷12 𝐷13 𝐷34


𝐷21 𝐷22 𝐷23 𝐷44
𝐷31 𝐷32 𝐷53 𝐷54
𝐷41 𝐷42 𝐷63 𝐷64
𝐷51 𝐷72 𝐷73 𝐷74
𝐷61 𝐷82 𝐷83 𝐷84
𝑃7 𝑃5 𝑃3 𝑃1
𝑃8 𝑃6 𝑃4 𝑃2

Fig. 4 – Organizarea datelor la arhitectura RAID 5 – varianta II.

În Fig. 4 s-a considerat că pentru paritate s-a rezervat ultima partiţie. Unele studii de evaluare a
performanţelor pentru arhitectura RAID 5 arată însă că este mai avantajos ca partiţia de paritate să
ocupe o poziţie mediană.

4
Actualizarea blocului de paritate

Actualizarea blocului de paritate se face la orice scriere a unor date în grupul de paritate. Sunt
trei situaţii distincte, ilustrate în Fig. 5, şi anume:
a) Sunt rescrise toate datele din grupul de paritate. Blocul de paritate este construit prin aplicarea
operatorului XOR asupra noilor blocuri de date.
b) Sunt actualizate mai puţin de jumătate din blocurile de date ce compun grupul de paritate. Să
presupunem că trebuie rescris blocul de date de pe discul 3. Noua valoare a blocului de paritate
𝑃𝑛 se obţine din vechea paritate 𝑃𝑣 , vechea şi noua dată de pe discul 3, 𝐷𝑣 şi 𝐷𝑛 , astfel că
𝑃𝑛 = 𝑃𝑣 ⊕ 𝐷𝑣 ⊕ 𝐷𝑛 . (3)

Astfel, în loc de 3 operaţii pentru citirea valorilor nemodificate de pe discurile 1, 2 şi 4 se fac doar
două operaţii de citire. Reducerea este şi mai mare când aria cuprinde mai multe discuri. În
relaţia (3), 𝑃𝑣 ⊕ 𝐷𝑣 reprezintă informaţia de control corespunzătoare datelor nemodificate.
c) Sunt actualizate jumătate sau mai mult de jumătate din blocurile de date ce compun grupul de
paritate (de exemplu, blocurile de date de pe discurile 2, 3, 4). Ca şi la punctul a) se face XOR
asupra tuturor datelor din grupul de paritate, cu diferenţa că pentru datele care nu sunt afectate
de scriere se citesc valorile curente.

Fig. 5 - Actualizarea blocului de paritate – cazurile a, b, c.

5
Trebuie remarcat faptul că actualizarea blocului de paritate implică un număr mare de operaţii
ceea ce afectează performanţele de timp de răspuns în sistemele de timp real tranzacţionale. Se
evidenţiază încă o dată legătura strânsă dintre cele trei elemente: timpul de răspuns, fiabilitatea şi
siguranţa în funcţionare.

Reconstituirea datelor în caz de eroare

Dacă un bloc de date nu poate fi citit, datele respective pot fi reconstituite prin citirea celorlalte
𝑁 blocuri din grupul de paritate şi aplicarea asupra lor a operatorului sau-exclusiv. În Fig. 6 este
ilustrat modul de reconstituire a datelor pierdute de pe discul 3.

𝐷3𝑟 – bloc de date reconstituit

Fig. 6 – Reconstituirea datelor în caz de eroare la citire.

Aşa cum se arată în figură, pentru reconstituirea blocului 𝐷3 afectat de eroare se aplică relaţia:
𝐷3𝑟 = 𝐷1  𝐷2  𝑃1234  𝐷4 = 𝐷1  𝐷2  (𝐷1  𝐷2  𝐷3  𝐷4 )  𝐷4 = 𝐷3 .

În expresie, blocurile 𝐷1 , 𝐷2 şi 𝐷4 apar în pereche şi se aplică regula 𝑥  𝑥 = 0.


Dacă un disc din cele 𝑁 + 1 este defect sistemul funcţionează normal, dar cu performanţe mai
reduse de timp de răspuns. Aceasta se explică prin faptul că pe durata cât un disc este defect,
celelalte 𝑁 discuri funcţionale sunt solicitate de două ori mai mult. Într-adevăr, dacă discul 𝑗 este
defect, cererile de citire adresate discului 𝑗 sunt redirectate către toate celelalte 𝑁 discuri pentru a
face posibilă reconstituirea datelor.
Fie 𝛿 rata medie a cererilor de citire a datelor memorate pe disc. Fiind solicitate uniform (în
special la varianta I de organizare a datelor), la o funcţionare normală rata medie a cererilor de citire
pentru un disc este
𝛿
𝛿𝑘 = 𝑁+1 , 𝑘 = 1, 2, … , 𝑁 + 1. (4)

Când discul 𝑗 este defect,


𝛿 𝛿 2𝛿
𝛿𝑘′ = 𝑁+1 + 𝑁+1 = 𝑁+1 , 𝑘 = 1, 2, … , 𝑁 + 1, 𝑘 ≠ 𝑗. (5)

întrucât la cererile adresate direct discului 𝑘 se adaugă cele redirectate de la discul defect. Aşadar
se poate spune că sistemul îşi continuă funcţionarea dar într-un regim de avarie.

6
Dacă aria de discuri este prevăzută cu un disc de rezervă, sistemul are capacitatea de
autoreparare, în paralel cu funcţionarea normală, fără o intervenţie din exterior. Discul defect este
înlocuit cu discul de rezervă (înlocuire “la cald”), datele fiind reconstituite în maniera prezentată.
Dacă în perioada de refacere a datelor pe noul disc apare o nouă eroare atunci există riscul ca
reconstituirea datelor pierdute să nu mai fie posibilă. Aşadar, această perioadă în care configuraţia
RAID5 nu mai are toleranţă la erori este o perioadă de vulnerabilitate. Dacă riscul de apariţie a unei
erori în perioada de vulnerabilitate rezultă din calcul că este prea mare, atunci trebuie adoptată
arhitectura RAID6, noul standard în prezent.

7
Evaluarea performanţelor privind
ariile de discuri magnetice

I. Aspecte privind evaluarea performanţelor de timp de acces

Aşa cum am s-a arătat anterior, menţinerea informaţiilor de control în vederea reconstituirii
datelor în caz de eroare conduce la o creştere semnificativă a numărului de operaţii cu discurile
magnetice şi, în consecinţă, a timpului mediu de acces în scriere. Să considerăm, ca exemplu, o arie
formată din 7+1 discuri magnetice în configuraţie RAID5, la care este implementată varianta I de
organizare a datelor (fişierele sunt distribuite de-a lungul ariei de discuri). Să presupunem că la o
operaţie de scriere trebuie actualizate 4 blocuri de date din cadrul unui grup de paritate. Pentru
actualizarea informaţiei de control se procedează aşa cum este ilustrat în Fig. 5 - c. Astfel, sunt
necesare în plus 3 operaţii de citire de pe discurile cu date nemodificate pentru determinarea noii
parităţi şi încă una de scriere pentru salvarea pe disc a acestei informaţii. În total, trebuie să se
realizeze 8 operaţii de lucru cu discul magnetic, 4 comandate de la nivelul aplicaţiei în derulare şi
altele 4 generate intern.
Pentru evaluarea performanţelor de timp de acces la aria de discuri magnetice, ansamblul de
discuri trebuie privit (modelat) ca un sistem de servire cu 𝑁 + 1 staţii care funcţionează în paralel.
Evaluarea performanţelor de timp de acces se face prin experimente de simulare. Discurile
magnetice sunt privite aşadar ca staţii de servire pentru cererile de transfer lansate de la nivelul
aplicaţiei. La construirea algoritmului de simulare trebuie să se ţină cont de următoarele aspecte:
1) O cerere de citire a unui bloc de date din fişier este descompusă în cereri simple, adresate
discurilor care memorează acel bloc. Operaţia se încheie când toate discurile implicate în
transfer au terminat. Evident, monitorizarea cererilor se realizează la nivelul driver-ului pentru
aria de discuri.
2) La scrierea unui bloc de date pe disc se impune şi actualizarea informaţiilor de control. Asta
presupune şi efectuarea unor operaţii suplimentare de scriere, dar și de citire. Prin urmare, o
parte din operaţiile de lucru cu discul sunt transmise din exterior, de la nivelul aplicaţiei, în timp
ce altele sunt generate intern.
3) Cererile de scriere în cadrul aceluiaşi grup de paritate sunt serializate întrucât blocul de paritate
este o resursă comună ce trebuie folosită prin excludere mutuală.
Ţinând cont de toate aceste aspecte, rezultă că organizarea aşteptării pentru lucrul cu discurile
magnetice implică formarea mai multor cozi de aşteptare, organizate pe niveluri, aşa cum este
ilustrat în Figura 9. Studiile privind performanţele de timp de acces la o structură RAID au evidenţiat
că este de preferat ca operaţiile ce privesc informaţia de control să se trateze cu prioritate. În
consecinţă, la nivelul discurilor magnetice se formează câte două cozi de aşteptare care să permită
tratarea operaţiilor după priorităţi.

8
1 𝑖 𝑁+1
+1
Discuri
𝑝 𝑑 𝑝 𝑑 𝑝 𝑑
Cozi
locale

Cozi dinamice, pe
grupuri de paritate

Legendă:
Cereri de scriere Coadă de aşteptare primară

Cereri de citire

𝜆 Cereri de transfer

Fig. 7 – Organizarea aşteptării la simularea funcţionării sistemului de discuri magnetice


în configuraţie RAID

Pentru determinarea timpului necesar unei operaţii de transfer simple, la nivelul unui disc
magnetic trebuie să se cunoască în permanenţă poziţia curentă a ansamblului de capete. Evident,
trebuie să se cunoască parametrii dinamici ai discului, care să permită calcularea timpului pentru
deplasarea ansamblului de capete de pe un cilindru pe altul şi a timpului de tranfer propriu-zis în
funcţie de mărimea blocului transferat. Pentru timpul de sincronizare cu începutul de bloc se poate
considera de fiecare dată jumătate din timpul necesar pentru o rotaţie completă.
Coada de aşteptare primară este reprezentată printr-un vector de structuri, în care pentru fiecare
cerere se reține momentul sosirii şi informaţiile de stare privind stadiul în care se află cererile simple,
rezultate din descompunerea cererii primare transmisă de la nivelul aplicaţiei.

II. Evaluări de fiabilitate privind ariile de discuri magnetice

Problema 1. De ce este necesară redundanţa

Fie un server care are în componenţa sa 𝑁 discuri magnetice identice. Pentru un disc, 𝑀𝑇𝐵𝐹 =
1
500.000 h (≈ 57 ani), iar rata de defectare este 𝜆 = 𝑀𝑇𝐵𝐹 = 210−6 ℎ−1 . Dacă intervalul de analiză
este [0, 𝑇], funcţia de fiabilitate este aşadar 𝑅 = 𝑒 −𝜆𝑇 . Pentru întregul ansamblu de discuri

9
magnetice în această formă neredundantă, funcţia de fiabilitate şi media timpului de bună
funcţionare sunt date de relaţiile:
𝑅𝑠𝑛 (𝑁, 𝜆, 𝑇) = 𝑅 𝑁 = 𝑒 −𝑁𝜆𝑇 , (6)
1
𝑀𝑇𝐵𝐹𝑠𝑛 = 𝑁𝜆 . (7)

Aşadar, media timpului de bună funcţionare scade proporţional cu numărul de discuri. De exemplu,
dacă 𝑁 = 10, 𝑀𝑇𝐵𝐹𝑠𝑛 = 5.7 ani (!).
Să facem un calcul numeric pentru 𝑇 = 1, 2 , 5 ani şi 𝑁 = 5, 10, 15 discuri.

Tabelul 1 – Fiabilitatea ariei de discuri în variantă neredundantă


𝑇 (ani) 𝑁=5 𝑁 = 10 𝑁 = 15
1 0.9100 0.8397 0.7684
2 0.8393 0.7044 0.5912
5 0.6453 0.4164 0.2687

Valorile scăzute din tabel evidenţiază că pentru sisteme de mare răspundere funcţională
implementarea unei tehnici de toleranţă de defecte, pentru creşterea fiabilităţii ariei de discuri, este
o necesitate absolută. De menţionat că această evaluare nu cuprinde şi erorile izolate ce pot apărea
în funcţionarea discurilor magnetice.

Problema 2. Configuraţia RAID5 fără facilităţi de reparare

Fie o arie formată din 𝑁 + 1 discuri magnetice în configuraţie RAID5. Să analizăm fiabilitatea acestei
structuri redundante fără a considera deocamdată facilitatea de reparare automată după înlocuirea
discului defect. Structura redundantă tolerează un disc defect din cele 𝑁 + 1, indiferent care. Prin
urmare, funcţia de fiabilitate a acestei structuri redundante poate fi exprimată cu relaţia:
(5)
𝑅𝑠𝑟 (𝑁 + 1, 𝜆, 𝑇) = 𝑅 𝑁+1 + (𝑁 + 1)𝑅 𝑁 (1 − 𝑅). (8)

Să reluăm calculul numeric cu valorile considerate anterior.

Tabelul 2 – Fiabilitatea ariei de discuri în configuraţie RAID5

𝑇 (ani) 𝑁=5 𝑁 = 10 𝑁 = 15
1 0.9957 0.9850 0.9692
2 0.9838 0.9469 0.9866
5 0.9159 0.7657 0.6068

Rezultatele numerice evidenţiază o creştere deosebită a fiabilităţii pentru aria de discuri în


configuraţie RAID5. Cu toate acestea, nivelul de siguranţă privind datele memorate pe disc este încă
insuficient. Un nivel de siguranţă corespunzător unor aplicaţii de mare răspundere funcţională nu
poate fi atins doar pe baza redundanţei. Mai mult, atunci când un disc este defect, chiar dacă
sistemul îşi continuă funcţionarea normală, regimul de lucru este unul de avarie, în care discurile

10
magnetice sunt solicitate de două ori mai mult, iar timpul de răspuns este afectat semnificativ.
Structura redundantă de tip RAID a fost concepută ca la defectarea unui disc acesta să fie înlocuit,
pentru ca sistemul să revină cât mai repede la starea de toleranţă şi la performanţele de timp de
răspuns de la început. Acesta este cazul ce trebuie analizat pentru că numai aşa se poate asigura o
fiabilitate ridicată şi o siguranţă deosebită privind datele memorate pe disc.

Problema 3. Configuraţia RAID5 cu facilităţi de reparare automată. Analiza vulnerabilităţii


La defectarea unui disc, acesta este înlocuit şi începe un proces de reconstituire a datelor
pierdute pe noul disc în maniera discutată anterior. Aşa cum s-a specificat, procesul de reconstituire
a datelor depinde de capacitatea discului, de lungimea ariei şi de ponderea timpului de procesor
alocată acestui proces în detrimentul aplicaţiei în derulare (parametru setabil). Ca ordin de mărime
această operaţie durează câteva ore. În analiza noastră vom considera că timpul mediu de
1
remediere 𝑇𝑟𝑚 = 4ℎ şi, ca urmare, intensitatea medie de remediere este 𝜇 = 4 = 0.25 ℎ−1 .
Pe durata procesului de reconstituire a datelor pierdute, cele 𝑁 discuri funcţionale sunt solicitate
într-o măsură mult mai mare decât în funcţionarea normală şi, în concecinţă, şi rata de defectare
este mai mare. Vom considera că în această perioadă de solicitare intensă rata de defectare este
𝜆′ = 4𝜆.
Analiza vulnerabilităţii sistemului în această perioadă trebuie să ia în considerare două aspecte:
a) Producerea unei noi defectări la unul din cele 𝑁 discuri în lucru;
b) Apariţia unei erori de tip CRC la citirea datelor de pe discurile funcţionale în vederea
reconstituirii datelor pierdute.
Să le analizăm pe rând.
➢ Probabilitatea de defectare a unui nou disc în perioada de remediere ( 𝑃𝑛𝑑 ) este dată de
relaţia:

𝑃𝑛𝑑 = 1 − 𝑒 −𝑁𝜆 𝑇𝑟𝑚 ≈ 𝑁𝜆′ 𝑇𝑟𝑚 . (9)

În tabelul următor se prezintă un calcul numeric.

Tabelul 3 – Probabilitatea unei noi defectări ( 𝑃𝑛𝑑 )

𝑁=5 𝑁 = 10 𝑁 = 15
𝑃𝑛𝑑 1.6 × 10−4 3.2 × 10−4 4.8 × 10−4

➢ Să evaluăm în continuare probabilitatea de apariţie a unei erori la citirea datelor de pe discurile


funcţionale (𝑃𝑒𝑟𝑐𝑑 ) în vederea reconstituirii datelor pierdute pe noul disc.
Ca urmare a unor limitări tehnologice, rata erorilor singulare ce pot apărea în exploatarea unui
disc magnetic este, conform specificaţiilor de catalog, de 1 bit eronat la 𝑋 = 1015 − 1016 biţi citiţi.
Unitatea elementară de lucru cu discul magnetic este însă sectorul. Să considerăm sectoare de 512
octeţi. La citirea unui sector se verifică suma de control calculată şi salvată anterior la sciere. Rata
𝑋
erorilor de tip CRC este aşadar de 1 la sectoare citite. Rezultă că probabilitatea citirii cu
512 × 8
512 × 8
succes a unui sector este de 1 − .
𝑋

11
Să considerăm o arie formată din 𝑁 + 1 discuri magnetice de 1TB. Capacitatea unui disc este de
1012
1TB = 1012 octeţi, ceea ce înseamnă că un disc are ≈ 2 × 109 sectoare.
512
Prin urmare, reconstituirea cu succes a noului disc implică citirea fără eroare a unui număr de
𝑁  2  109 sectoare. Probabilitatea unei erori la citirea acestor date se poate exprima cu relaţia
9
512  8 𝑁 210 512  8
𝑃𝑒𝑟𝑐𝑑 = 1 − (1 − ) ≈  𝑁  2  109 . (10)
𝑋 𝑋

În Tabelul 4 se prezintă un calcul numeric.

Tabelul 4 – Probabilitatea unei erori la citirea datelor (𝑃𝑒𝑟𝑐𝑑 )

𝑁=5 𝑁 = 10 𝑁 = 15
𝑋 = 1015 0.0401 0,0787 0.1156
𝑋 = 1016 0.0041 0.0082 0.0122

Valorile din tabel evidenţiază faptul că apariţia acestor erori, deseori neglijate, are o probabilitate
mult mai mare. Este însă adevărat că la defectarea unui disc consecinţele sunt mult, mult mai grave.
La varianta I de organizare a datelor, când fişierele sunt distribuite de-a lungul ariei de discuri, cu
defectarea şi a celui de-al doilea disc pot fi pierdute toate datele memorate pe aria de discuri. De
aceea, trebuie realizate periodic versiuni de back-up.
De asemenea, valorile numerice din Tabelul 4 evidenţiază faptul că o rată a erorilor de 1 bit la 𝑋 =
1015 biţi citiţi este prea mare şi trebuie exclusă. Aşadar, în continuare vom considera numai discuri
pentru care 𝑋 = 1016 .
Cu aceste două evaluări, putem determina probabilitatea reconstituirii cu succes a datelor pe noul
disc (𝑃𝑟𝑠 ) cu relaţia:

𝑃𝑟𝑠 = (1 − 𝑃𝑛𝑑 ) (1 − 𝑃𝑒𝑟𝑐𝑑 ) (11)

Cu aceste elemente, putem determina cu acurateţe fiabilitatea unei arii de discuri magnetice în
configuraţie RAID5, pe un interval de timp [0, 𝑇] specificat. Pierderea de date poate apărea atunci
când se defectează un disc şi procesul de reconstituire a datelor pierdute nu se încheie cu succes.
Pe baza acestui raţionament, putem scrie relaţia finală:
(5)
𝑅𝑠𝑟 (𝑁 + 1, 𝑇) = 1 − (1 − 𝑅(𝑇)𝑁+1 )(1 − 𝑃𝑟𝑠 ) (12)

În tabelul următor se prezintă rezultate numerice pentru o perioadă de cinci ani.

(5)
Tabelul 5 – Fiabilitatea ariei de discuri (𝑅𝑠𝑟 (𝑁 + 1, 𝑇))

𝑇 = 5 ani 𝑁=5 𝑁 = 10 𝑁 = 15
𝑋 = 1016 0.9953 0.9915 0.9873

12
Pe baza acestor rezultate numerice se pot trage câteva concluzii:
• Siguranţa datelor memorate pe disc pare să fie încă insuficientă. Aşa se explică de ce în prezent,
când capacitatea discurilor este mare, noul standard pentru aplicaţii de mare răspundere
funcţională este RAID 6, care tolerează două discuri defecte din aria formată din 𝑁 + 2 discuri.

• Odată cu creşterea lui 𝑁 nivelul de redundanţă este mai redus şi prin urmare şi fiabilitatea este
mai mică. De aceea, aria de discuri trebuie dimensionată corespunzător. Cu datele numerice
considerate în această analiză, rezultă că 15 discuri la o singură arie în configuraţie RAID5 sunt
prea multe. Când necesarul de memorie este mare, trebuie să se formeze mai multe arii de
discuri independente, dimensionate corespunzător.

13
STR - Partea a II-a
Programarea aplicaţiilor de timp real

1. Elemente de bază privind programarea concurentă

Dacă un program reprezintă descrierea formală a unor structuri de date şi algoritmi,


conform unui formalism convenţional, un proces reprezintă activitatea rezultată din
executarea unui program pe un sistem de calcul.
Un program secvenţial descrie un singur proces, în timp ce un program concurent descrie
mai multe procese care să fie executate în paralel. Mai multe procese sunt paralele dacă
executarea lor se suprapune în timp. Întrucât aceasta nu implică neapărat executarea
concomitentă (pe un sistem de calcul monoprocesor acest lucru nici nu este posibil), o
definiţie mai precisă este următoarea: două procese sunt paralele dacă prima instrucţiune a
unui proces este lansată înaintea ultimei instrucţiuni a celuilalt proces. Cu alte cuvinte,
paralelismul în executarea proceselor semnifică faptul că la un moment dat pot fi active
(începute şi neterminate) mai multe procese, care concurează pentru obţinerea resurselor
necesare executării lor. Întrucât sunt părţi ale aceleiaşi aplicaţii, procesele concurente
trebuie să „colaboreze” sau să „interacţioneze” pe parcursul desfăşurării lor. Conceptul de
concurenţă între procese a fost introdus pentru a defini atât paralelismul, cât şi interacţiunea
dintre ele:

Concurenţă = Paralelism + Interacţiune

Paralelismul fără interacţiune reprezintă cazul particular al multiprogramării, util doar


pentru o utilizare eficientă a sistemului de calcul, când programe independente rulează din
punct de vedere logic ca şi cum ar beneficia fiecare de întregul sistem. Conceptul de
concurenţă exprimă atât sensul de competiţie pentru obţinerea resurselor necesare
executării lor, cât şi sensul de convergenţă, procesele lucrând la realizarea aceleiaşi aplicaţii.
Concurenţa ridică probleme de alocare a resurselor comune (unitate centrală, memorie,
variabile comune, fişiere partajate etc.) şi de evitare a situaţiilor de interblocare ce ar putea
apărea. Pe parcursul acestui curs, cele două concepte de „proces paralel” şi „proces
concurent” vor fi considerate echivalente.
În programarea concurentă, componenta de bază este o entitate a cărei structură (şi
implicit denumire) poate să difere de la un caz la altul. Termeni folosiţi: proces, task,
program activ etc. Indiferent însă de structură, entitatea are următoarele proprietăţi
invariante:
• Este atomică în sensul că nu mai poate fi descompusă în alte unităţi cărora sistemul
de operare să le aloce resurse;
• În interior totul este consecutiv, nu există paralelism;
• Se desfăşoară cu o viteză necorelată cu a altor entităţi paralele, sincronizându-se
explicit cu acestea în caz de nevoie;
• Există şi este recunoscută ca atare numai între momentul lansării în execuţie şi
terminare.

1
Sisteme de timp real

1.1 Stările proceselor

Stările proceselor şi tranziţiile dintre ele sunt prezentate în figura următoare.

În execuţie

Gata de Inactiv
execuţie

Blocat

Fig. 1 - Stările proceselor şi tranziţiile dintre ele.

Semnificaţia stărilor este prezentată în continuare.


• Starea în execuţie este caracteristică procesului care controlează la un moment dat
unitatea centrală .
• Spunem despre un proces care se află în aşteptare pentru controlul unităţii centrale
(în aşa numita listă ready) că este gata de execuţie.
• Un proces rezident în memoria externă este inactiv. Acesta poate fi activat printr-o
comandă de la terminal sau de către un alt proces în execuţie.
• Un proces care trebuie să aştepte îndeplinirea unei condiţii necesare continuării
execuţiei este trecut în starea blocat. Procesul poate să aştepte alocarea unui spaţiu de
memorie, terminarea unei operaţii de intrare/ieşire, sincronizarea cu un alt proces,
trecerea unui anumit interval de timp, eliberarea unei resurse etc.
Tranziţia din starea gata de execuţie în starea blocat, mai puţin frecventă, corespunde
situaţiei când procesul este evacuat temporar din memorie pentru asigurarea unui volum
mai mare de memorie procesului în execuţie.

1.2 Interacţiunea proceselor

Interacţiunea între procese cuprinde două aspecte:


• Comunicarea – când un proces foloseşte date rezultate din activitatea unui alt proces;
• Sincronizarea – când mai multe procese folosesc în comun o resursă şi trebuie să
respecte o anumită disciplină în exploatarea ei, sau când continuarea executării unui
proces depinde de starea în care se află un alt proces.
În principiu, există două forme de comunicare a informaţiei între procese:
• Prin transfer direct – informaţia este copiată dintr-o zonă de memorie a unuia într-
o zonă de memorie a celuilalt.

2
Sisteme de timp real

Informaţia Informaţia
Canal S. O. Canal
originală copiată

Proces 1 Proces 2

Fig. 2 – Comunicarea prin transfer direct.

• Prin variabile comune (sau partajate) – partajarea se poate face între oricâte procese.

scriere citire
Variabile
Proces 1 citire scriere Proces 2
comune

Proces m

Fig. 3 – Comunicarea prin variabile comune.

Conceptul de variabilă comună are o accepţiune largă, reprezentând orice entitate


recunoscută de program (variabilă simplă, tablou, fişier etc.) la care au acces în citire şi, de
regulă, şi în scriere mai multe procese. Folosirea variabilelor comune constituie o soluţie
care asigură viteză, flexibilitate şi eficienţă ridicată. Cu toate acestea, accesul la variabilele
comune trebuie bine reglementat, altfel existând pericolul ca pentru aceleaşi date de intrare
rezultatele executării programului să difere de la o rulare la alta.
În afară de măsurile necesare asigurării comportării reproductibile a programelor,
folosirea variabilelor comune de către mai multe procese mai are şi un alt dezavantaj major,
şi anume faptul că modificările în descrierea unui proces pot avea consecinţe greu de evaluat
pentru aplicaţia în ansamblu.
Noţiunea de sincronizare între procese are un sens larg, de coordonare în timp, de
corelare. Sensul iniţial de simultaneitate se păstrează numai ca un caz particular. Astfel, pot
să fie sincronizate două procese care nu se suprapun în timp, cum ar fi un proces care
durează 1 secundă şi se lansează cu 2 secunde înaintea celuilalt. În schimb, dacă procesele
se desfăşoară în general în paralel, dar nici un moment al unuia nu este corelat cu vreun
moment al celuilalt, ele se consideră asincrone.
Sensul de coordonare în timp presupune nu numai o relaţie temporală, ci şi stabilitatea
ei, în sensul că relaţia se menţine la fiecare executare, indiferent că exprimă simultaneitate
sau decalaj. Aşadar, sincronizarea implică predictibilitate şi este un mijloc de contracarare
a nedeterminismului specific aplicaţiilor de timp real − nedeterminism dat de natura
aleatoare a evenimentelor externe şi de vitezele inegale şi variabile în timp de executare a
proceselor.

3
Sisteme de timp real

Sincronizarea trebuie să permită activarea sau stoparea desfăşurării unor procese, atât
prin cereri iniţiate de procese în execuţie, cât şi din exterior, de exemplu de la terminal.
Întreruperea continuării trebuie să fie posibilă şi din interiorul procesului, urmând ca
reactivarea să se facă, evident, din exterior.
Sincronizarea este de două feluri:
• implicită: mai multe procese partajează o resursă şi trebuie să respecte disciplina
accesului;
• explicită: un proces trebuie să aştepte până când un alt proces termină o anumită
activitate (continuarea executării lui depinde de starea altui proces); durata aşteptării
este de regulă impredictibilă – se mai numeşte şi sincronizare pe condiţie.
Din cele prezentate anterior rezultă o legătură organică între comunicare şi sincronizare.
Pentru consistenţa comunicării, sincronizarea este indispensabilă, cel puţin în sensul că
emiterea unei date precede recepţia ei. Şi reciproc, sincronizarea impune cel puţin
comunicarea faptului că un eveniment s-a produs (în mod natural două entităţi „se întâlnesc”
pentru că au să-şi comunice ceva).
Aşa cum s-a arătat anterior, comunicarea prin variabile comune presupune ca mai multe
procese să aibă acces la aceleaşi variabile, în vederea utilizării sau modificării lor. Să
considerăm o aplicaţie de timp real formată din mai multe procese concurente, la care se
doreşte contorizarea comenzilor externe emise de întreaga aplicaţie în sistemul condus. În
acest scop se foloseşte o variabilă comună contor ce trebuie incrementată după fiecare
comandă în cadrul fiecărui proces. Incrementarea contorului (contor = contor + 1) se
traduce în limbaj maşină prin trei instrucţiuni:

încarcă contor
adună 1
memorează contor

Din executarea întreţesută a proceselor poate rezulta următoarea secvenţă de operaţii:

încarcă contor /* proces 1 */


încarcă contor /* proces 2 */
adună 1 /* proces 2 */
memorează contor /* proces 2 */
adună 1 /* proces 1 */
memorează contor /* proces 1 */

Efectul este incrementarea contorului cu 1, evident eronat. Pentru a asigura funcţionarea


corectă a sistemului, este necesar ca un singur proces să execute la un moment dat secţiunea
de program pentru incrementarea contorului.
O resursă care trebuie utilizată doar de un singur proces la un moment dat se numeşte
resursă critică. Secţiunea de program care utilizează o resursă critică sau operează asupra
unei resurse critice se numeşte secţiune sau regiune critică.

4
Sisteme de timp real

Definim excluderea mutuală (sau reciprocă) ca fiind acea formă de sincronizare impusă
proceselor concurente care permite ca numai un proces să se afle în interiorul unei regiuni
critice la un moment dat. O soluţie corectă a problemei excluderii mutualte trebuie să
îndeplinească următoarele condiţii:
C1 – O resursă critică poate fi utilizată la un moment dat de către un singur proces (un
singur proces se poate afla în interiorul regiunii critice corespunzătoare resursei la un
moment dat) – consecinţă directă a celor trei definiţii anterioare.
C2 – Procesele care sunt pe punctul de a trece la executarea secţiunilor lor critice nu
trebuie să se blocheze reciproc la infinit. Cu alte cuvinte, alegerea unuia dintre procesele
care solicită simultan să intre într-o regiune critică trebuie să se facă într-un timp finit.
C3 – Un proces care se găseşte în afara regiunii sale critice nu poate opri un alt proces să
intre într-o regiune critică.
C4 – Condiţiile C1-C3 trebuie asigurate fără să se facă vreo ipoteză cu privire la viteza
relativă de executare a proceselor.
Ca o remarcă, regiunile critice trebuie să fie cât mai scurte deoarece pot să întârzie în
execuţie alte procese.

1.3 Reprezentarea cu reţele Petri a interacţiunii între procesele concurente

La reprezentarea cu reţele Petri a proceselor concurente, locaţiile descriu de regulă adrese


particulare din program, în timp ce tranziţiile reprezintă instrucţiuni/primitive cu rol în
sincronizarea dintre procese. De exemplu, adresa de început a unei secţiuni critice poate fi
evidenţiată printr-o locaţie, iar marcajul în acea locaţie reflectă faptul că procesul descris
este pe punctul de a intra în secţiunea critică. Tot printr-o locaţie este descris, de exemplu,
şi un semafor. Marcajului iniţial pentru o astfel de locaţie reprezintă valoarea de iniţializare
a semaforului.
Pentru descrierea interacţiuniilor dintre procesele concurente se foloseşte o extensie a
reţelelor Petri cu facilităţi adecvate. Astfel, acest formalism permite introducerea unor
variabile suplimentare, numite variabile program, distincte de cele cu semnificaţie de
marcaj. Ȋn consecinţă şi regula tranziţiei poate fi extinsă. Astfel, unei tranziţii din reţea i se
poate asocia un predicat de permisiune a executării, cu rol de gardă, şi o funcţie de acţiune
asupra variabilelor program. Tranziţia nu poate fi executată cât timp predicatul de
permisiune are valoarea false (garda este închisă).
De remarcat că vectorul marcaj arată starea fluxului de control în executarea proceselor
concurente, în timp ce vectorul variabilelor program reflectă starea fluxului de date.
Folosirea reţelelor Petri oferă posibilităţi suplimentare de verificare a interacţiunilor
dintre procesele concurente. De exemplu, o situaţie de interblocaj poate fi evidenţiată prin
găsirea unei stări în care nicio tranziţie nu este validată.

5
Sisteme de timp real

Sincronizarea proceselor folosind semafoare

Mecanismul de sincronizare între procese bazat pe semafoare a fost propus de Dijkstra în


1968 pentru a înlătura neajunsurile sincronizării explicite prin program (structura stufoasă
a secvenţei de sincronizare şi aşteptarea activă prin testarea în buclă a unor variabile de
stare).
Un semafor este un cuplu (𝑠, 𝑓(𝑠)), implementat la nivelul sistemului de operare, în care:
• 𝑠 este o variabilă întreagă nenegativă;
• 𝑓(𝑠) este un şir de aşteptare asociat variabilei s în care pot fi blocate procese care
aşteaptă îndeplinirea unei condiţii necesare continuării lor.
Fie o resursă partajată căreia i se asociază un semafor. Resursa partajată are o
semnificaţie logică, reprezentând una sau mai multe resurse fizice de acelaşi tip. Numărul
lor este specificat la iniţializarea semaforului. Asupra semaforului pot fi executate doar două
primitive, 𝑃 şi 𝑉: 𝑃 - pentru a solicita accesul la resursă şi 𝑉 - pentru a semnala eliberarea
resursei. Primitivele sunt rutine neîntreruptibile de program implementate la nivelul
nucleului sistemului de operare pe durata cărora sistemul de întreruperi este dezactivat.
Aşadar, primitivele pot fi privite ca o extensie a setului de instrucţiuni pentru procesor.
Structura celor două primitive:
P (s ) : if (s == 0) 
# blochează procesul curent;
# înregistrează procesul în şirul de aşteptare 𝑓(𝑠);
/* acesta va aştepta până când o operaţie 𝑉(𝑠) îl va relansa */

else 𝑠 − −; // permite accesul la resursă

V (s ) : if ( f (s )   )
# relansează un proces din şirul de aşteptare 𝑓(𝑠);
else 𝑠 + +; // marchează eliberarea resursei

Variabila întreagă 𝑠 semnifică numărul de resurse fizice disponibile şi poate fi


reprezentată printr-o locaţie la o descriere cu reţele Petri a sincronizării între procese.
Datorită caracterului foarte general, semafoarele permit rezolvarea oricărei probleme de
sincronizare, atât pentru excluderea mutuală cât şi pentru sincronizarea pe condiţie.
Excluderea mutuală se realizează prin intermediul unui semafor binar. Secţiunile critice
trebuie încadrate între primitivele 𝑃 şi 𝑉.
var 𝑠: semaphore: = 1;

// proces 𝑖 // proces 𝑗
---------- ----------
𝑃(𝑠); 𝑃(𝑠);
# secţiune critică (𝑆𝐶𝑖 ) # secţiune critică (𝑆𝐶𝑗 )
𝑉(𝑠); 𝑉(𝑠);
---------- ----------

6
Sisteme de timp real

proces 𝑖 proces 𝑗

s
𝑃(𝑠) 𝑃(𝑠)

𝑆𝐶𝑖 𝑆𝐶𝑗

𝑉(𝑠) 𝑉(𝑠)

Fig. 4 - Excluderea mutuală între procese.

Pentru sincronizarea pe condiţie între două procese se foloseşte un semafor iniţializat cu 0.


Când condiția nu este îndeplinită, un proces se pune în aşteptare executând o operaţie 𝑃
asupra semaforului, urmând ca un alt proces să îl relanseze printr-o operație 𝑉, după ce
constată îndeplinirea condiţiei. Secvenţa următoare de program şi reţeaua Petri din Fig. 5
evidențiază acest mecanism de sincronizare pe condiţie.

var 𝑠: semaphore: = 0;
----------
// proces 𝑖
----------
𝑃(𝑠);
----------

// proces 𝑗
----------
if 𝑐𝑜𝑛𝑑 = 𝑇𝑟𝑢𝑒 then 𝑉(𝑠);
----------

s
P(s) V(s)
(cond = T) (cond = F)

Fig. 5 - Sincronizarea pe condiţie.

7
Sisteme de timp real

3. Exemple

1. Problema „producători – consumatori”


Să analizăm un mecanism de sincronizare care să permită unui număr oarecare 𝑛𝑝 de
procese producător să furnizeze mesaje unui număr oarecare 𝑛𝑐 de procese consumator,
printr-un buffer circular cu 𝑛 locaţii. Mesajele sunt de acelaşi tip, astfel că producătorii nu
generează mesaje pentru un consumator anume şi nici consumatorii nu sunt interesaţi de
provenienţa mesajelor preluate. Structura buffer-ului este prezentată în figură.

locaţii libere (L) locaţii ocupate (O)

n-1 1 0

l o

Fig. 3 – Structura buffer-ului.

Semnificaţia variabilelor cursor l şi o:


𝑙 - indicele primei locaţii libere, în care se va depune următorul mesaj; variabila este
iniţializată cu 0 şi nu are semnificaţie când buffer-ul este plin.
𝑜 - indicele locaţiei ocupate cu cel mai vechi mesaj nepreluat, din care se va extrage
următorul mesaj; variabila, iniţializată cu 0, nu are semnificaţie când buffer-ul este gol.

Analiza detaliată a problemei


Fără un control adecvat la transferul mesajelor prin buffer pot apărea mai multe erori, şi
anume:
• deteriorarea mesajelor ca urmare a accesării simultane a unei locaţii de către mai multe
procese.
• pierderea mesajelor prin suprascriere – într-o locaţie se depune un mesaj fără ca cel
depus anterior să fi fost preluat;
• citirea aceluiaşi mesaj de mai multe ori.
Pentru controlul accesului la buffer se introduce un semafor binar notat cu 𝑎. Astfel,
accesul la buffer se va face prin excludere mutuală între procese.
În vederea evitării suprascrierii, producătorii trebuie opriţi (blocaţi) la încercarea de
depunere a unui nou mesaj când buffer-ul este plin. Pentru procesele producător, o locaţie
liberă în buffer reprezintă o resursă necesară continuării executării lor. Pentru controlul
alocării acestor resurse se introduce un semafor 𝐿 iniţializat cu 𝑛.
Pentru ca un mesaj să nu fie citit de mai multe ori, consumatorii trebuie blocaţi atunci
când încearcă să citească un mesaj deja preluat. Pentru procesele consumator un mesaj
neprelut constituie o resurnă necesară continuării executării lor. Pentru controlul accesului
la mesajele din buffer se introduce un semafor 𝑂 iniţializat cu 0.

8
Sisteme de timp real

Mecanismul de sincronizare între procese este ilustrat prin următoarea reţeaua Petri.

producători consumatori
np nc
L
n
P(L) P(O)

P(a) P(a)
a
“depune” “extrage”

V(a) V(a)

O
V(O) V(L)

Fig. 4 – Reţea Petri pentru problema „producători-consumatori”.

Secvenţa de program care cuprinde operaţiile celor două procese pentru lucrul cu buffer-
ul este următoarea:
mesaj 𝑏𝑢𝑓𝑓𝑒𝑟 [𝑛] ;
int 𝑙 = 0, 𝑜 = 0;
semafor 𝑎 = 1, 𝐿 = 𝑛, 𝑂 = 𝑜;
cobegin
----------
// (* producător *) //(* consumator *)
mesaj 𝑚; mesaj 𝑚;
---------- ----------
produce (&𝑚);
𝑃(𝐿); 𝑃(𝑂);
𝑃(𝑎); 𝑃(𝑎);
𝑏𝑢𝑓𝑓𝑒𝑟 [𝑙] = 𝑚; 𝑚 = 𝑏𝑢𝑓𝑓𝑒𝑟 [𝑜];
𝑙 = (𝑙 + 1) % 𝑛; 𝑜 = (𝑜 + 1) % 𝑛;
𝑉(𝑎); 𝑉(𝑎);
𝑉(𝑂); 𝑉(𝐿);
---------- ----------
coend;

9
Sisteme de timp real

Problema „producători – consumatori” - Soluţie îmbunătăţită

Soluţia anterioară este corectă dar sincronizarea între procese este prea strânsă. O soluţie
mai eficientă se obţine plecând de la faptul că o operaţie de depunere şi una de extragere se
pot executa în paralel dacă se lucrează cu locaţii diferite.
Analizând variabilele cursor 𝑙 şi 𝑜 rezultă faptul că acestea sunt egale numai atunci când
buffer-ul este plin sau când buffer-ul este gol. Dar, în aceste două situaţii, producătorii sau
consumatorii, după caz, sunt împiedicaţi să acceseze buffer-ul. Prin urmare, excluderea
mutuală trebuie să se limiteze la procese de acelaşi tip. Pentru serializarea accesului la buffer
a producătorilor se introduce semaforul 𝑤, iar a consumatorilor, semaforul 𝑟. Mecanismul
de sincronizare între procese este descris de următoarea reţea Petri.

np L nc
n
P(L) P(O)

P(w) P(r)

w r
O

V(w) V(r)

V(O) V(L)

Fig. 5 Reţea Petri pentru problema „producători-consumatori” – varianta II.

Secvenţa de program este următoarea:


mesaj 𝑏𝑢𝑓𝑓𝑒𝑟 [𝑛];
int 𝑙 = 0, 𝑜 = 0;
semafor 𝑤 = 1, 𝑟 = 1, 𝐿 = 𝑛, 𝑂 = 𝑜;
cobegin
// (* producător *) // (* consumator *)
mesaj 𝑚; mesaj 𝑚;
produce (&𝑚);
𝑃(𝐿); 𝑃(𝑂);
𝑃(𝑤); 𝑃(𝑟);
𝑏𝑢𝑓𝑓𝑒𝑟 [𝑙] = 𝑚; 𝑚 = 𝑏𝑢𝑓𝑓𝑒𝑟 [𝑜];
𝑙 = (𝑙 + 1) % 𝑛; 𝑜 = (𝑜 + 1) % 𝑛;
𝑉(𝑤); 𝑉(𝑟);
𝑉(𝑂); 𝑉(𝐿);
prelucreaza (m);
---------- ----------
coend;

10
Sisteme de timp real

Exemplul 2 - Partajarea unui fişier

Ne propunem să realizăm un mecanism de control privind accesul la un fişier partajat


de către mai multe procese concurente, care să respecte următoarele specificaţii
(disciplina de acces):
• Accesul la fişier pentru efectuarea unei operaţii de scriere trebuie să se facă prin
excludere mutuală între procese;
• Citirea simultană din fişier este permisă pentru oricâte procese;
• Operaţiile de lucru cu fişierul trebuie să aibă loc în ordinea solicitărilor.

➢ Analiza detaliată a problemei

a) De ce este necesar controlul privind accesul la fişier


Dacă accesul la fişier s-ar face fără restricţii în cadrul proceselor, lăsând doar controlul
implementat la nivelul sistemului de operare (al subsistemului de gestiune a fişierelor),
pe durata cât fişierul este indisponibil procesele trebuie să rămână într-o buclă de forma
while ((fp = fopen (nume_fişier, mod_de_acces)) == NULL) ;
până la eliberarea lui.
Acest lucru este de natură să reducă viteza de rulare a aplicaţiei, afectând astfel
performanţele de timp de răspuns.
Prin urmare, mecanismul de control pe care îl avem în vedere urmăreşte blocarea
proceselor care solicită accesul la fişier cât timp acest acces nu este posibil sau nu este
permis. De asemenea, mecanismul trebuie să impună şi accesul la fişier strict în ordinea
solicitărilor.
b) Organizarea aşteptării
Deoarece se impune ca accesul la fişier să se facă în ordinea solicitărilor, procesele care
aşteaptă acceptul de acces la fişier trebuie blocate într-o coadă de aşteptare comună,
indiferent de tipul operaţiei solicitate, aşa cum este ilustrat în figura următoare.

A
sau
u

Figura 6 – Organizarea aşteptării într-o coadă comună.

Poarta de acces A şi coada de aşteptare asociată poate fi implementată cu un semafor


binar (notat la fel). Mecanismul bazat pe semafoare vine în întâmpinarea implementării
acestei cerinţe. În figură, cererile de acces în scriere (procesele scriitor) sunt reprezentate
prin puncte albe, iar cele de acces în citire (procesele cititor), prin puncte negre. Fişierul
poate fi deschis de un singur proces care solicită efectuarea de operaţii de scriere, sau de
unul sau mai multe procese care efectuează doar operaţii de citire.

11
Sisteme de timp real

Variabila de stare ca reflectă numărul de procese care accesează fişierel în citire la un


moment dat.
Figura 6 ilustrează un mecanism de control privind accesul la fişier cu o singură gardă.
Să verificăm acest mecanism de control. După o solicitare de acces la fişier în scriere,
accesul trebuie apoi blocat până când fişierul este închis şi devine astfel disponibil pentru
o nouă solicitare. În acest caz mecanismul cu o singură gardă este adecvat. Problema
apare însă după o solicitare de acces în citire. Mai precis, dacă garda se închide, accesul
altor cereri de acces în citire nu mai este permis, contrar disciplinei de acces, iar dacă
garda rămâne deschisă, soluţia este greşită atunci când următoarea cerere de acces este
una de scriere în fişier. Prin urmare, o soluţie de control cu o singură gardă nu este
posibilă.
Pentru a depăşi inconvenientul menţionat anterior, se propune ca pentru o cerere de
acces în scriere decizia să se ia în două trepte, aşa cum este ilustrat în Figura 7. Astfel, se
verifică mai întâi dacă poarta de acces A este deschisă, iar apoi dacă fişierul nu este accesat
în citire de către alte procese. Într-o astfel de situaţie, accesul altor cereri de acces la fişier
sunt blocate, dar procesele în curs de citire din fişier sunt aşteptate, în locaţia asociată
porţii de acces w, până când fişierul devine disponibil. În cazul unei cereri de acces în
citire, procesul aşteaptă dacă accesul nu este posibil, sau nu este permis, dar după
primirea acceptului poarta de acces A rămâne deschisă.

w
ca = 0
A
ca > 0

ca

Figura 7 – Accesul la fişier cu decizie în două trepte pentru scriere.

Un astfel de mecanism cu decizie în două trepte pentru accesul în scriere răspunde


celor trei cerinţe privind disciplina de acces. Pentru exemplificare, în continuare se
prezintă evoluţia privind accesul la fişier pentru procesele în aşteptare. Figura 8 ilustrează
această evoluţie. Mai întâi, toate procesele în aşteptare rămân blocate până când cele 3
procese care citesc din fişier termină operaţia şi eliberează fişierul. Când variabila de stare
ca devine 0, procesul care aşteaptă la poarta de acces w este relansat pentru a efectua
operaţia de scriere în fişier. Figura 8–a evidenţiază această stare.

a) Eliberarea fişierului de către procesele cititor permite începerea scrierii

12
Sisteme de timp real

b) La eliberarea fişierului, după scriere, se redeschide poarta de acces A

c) Scrierea se face prin excludere mutuală.

d) Procesele cititor sunt reactivate în grup iar procesul scriitor trebuie să aştepte.

Figura 8 – Evoluţia aşteptării proceselor pentru accesul la fişier.

După actualizarea fişierului şi eliberarea lui, poarta principală de acces 𝐴 se redeschide


(Figura 8-b). Urmează o nouă operaţie de scriere în fişier care se face prin excludere
mutuală. Astfel, poarta de acces 𝐴 se închide din nou şi celelalte procese care solicită accesul
la fişier în citire rămân blocate (Figura 8-c). După terminarea scrierii şi eliberarea fişierului,
poarta principală de acces se redeschide ceea ce permite grupului de procese cititor să aibă
acces simultan la fişier. Pentru că procesele cititor lasă poarta de acces deschisă va trece de
această gardă şi următorul proces scriitor. Acesta va închide poarta de acces 𝐴 dar va găsi
garda închisă la poarta de acces secundară 𝑤. Se ajunge astfel într-o starea oarecum similară
cu cea de la care am plecat (Fig. 8-d).
Pentru implementarea acestei soluţii sunt necesare trei semafoare binare: 𝐴 şi 𝑤 pentru
implementarea celor două gărzi (sau porţi de acces) şi un semafor de lucru, notat cu 𝑐,
pentru asigurarea actualizării variabilei de stare 𝑐𝑎 prin excludere mutuală, de către
procesele care au acces la fişier în citire.

➢ Descrierea acestui mecanism de acces de tip FIFO


Să notăm cu ns şi nc numărul maxim de procese care pot solicita accesul la fişier în scriere,
respectiv în citire. Mecanismul de sincronizare între procese care asigură controlul accesului

13
Sisteme de timp real

la fişier conform acestei disciplinei de tip FIFO este prezentat sub formă de reţea Petri în
figura următoare.

Figura 9 – Sincronizarea între procese pentru accesul la fişier


după o disciplină FIFO.

Formalismul de descriere a mecanismului de sincronizare între procese cu reţele Petri


permite o verificare uşoară şi riguroasă a soluţiei propuse. De exemplu, urmărind locaţiile 𝐴
şi 𝑤 şi tranziţiile aferente, se verifică uşor că scrierea în fişier se face prin excludere mutuală,
sau faptul că pentru citire se permite accesul în paralel pentru oricâte procese. De asemenea,
formarea unei singure cozi de aşteptare în spatele porţii principale de acces 𝐴 garantează
accesul la fişier în ordinea solicitărilor.
Secvenţa de program prin care se implementează acest mecanism este prezentată în
Pseudocodul următor.

14
Sisteme de timp real

int ca = 0; || (* proces concurent*)


semaphore A=1, w=1, c=1;
// accesul la fișier în citire
cobegin
.....
|| (* proces concurent*) 𝑃(𝐴);
// accesul la fișier în scriere 𝑃(𝑐);
..... ca++;
𝑃(𝐴); if (ca == 1) 𝑃(𝑤);
𝑃(𝑤); 𝑉(𝑤); 𝑉(𝑐);
#deschide fişier în scriere V(𝐴);
#actualizează fişier #deschide fişier în citire
#închide fişier #citeşte fişier
𝑉(𝐴); #închide fişier
.....
𝑃(𝑐);
ca --;
if (ca == 0) 𝑉(𝑤);
𝑉(𝑐);
.....
coend.

Pseudocod 1 - Sincronizarea între procese pentru accesul la fişier după o disciplină FIFO

Concluzii privind semafoarele

Semafoarele cu primitivele 𝑃 şi 𝑉 permit rezolvarea performantă (fără aşteptare activă) şi


uneori elegantă a problemelor de sincronizare dintre cele mai diverse. Gradul de generalitate
se datorează însă nivelului lor scăzut şi datorită acestui fapt utilizarea lor implică o mare
atenţie din partea programatorului. Omiterea unei primitive 𝑉 , de exemplu, poate avea
consecinţe deosebit de grave, lăsând o resură blocată şi procese suspendate pe o perioadă
timp nelimitată.
De remarcat că nu există o legătură explicită între un semafor şi resursa pentru care se
realizează controlul accesului. De aceea, compilatorul nu poate face nici un fel de verificări
asupra modului în care sunt folosite resursele partajate.
Ambele forme de sincronizare, excluderea mutuală şi sincronizarea explicită pe condiţie,
se rezolvă deopotrivă cu primitivele 𝑃 şi 𝑉. Aceasta nu este de natură să crească claritatea
programelor. Mai mult, primitivele 𝑃 şi 𝑉 asociate unei resurse sau unei condiţii aparţin de
procese diferite, identificarea lor fiind anevoioasă.

15
STR Cursul 12

Regiuni critice simple şi condiţionale

Pentru a reduce riscurile erorilor de programare pe care le implică folosirea semafoarelor,


s-a propus o nouă construcţie pentru sincronizarea între procese, specifică limbajelor de
programare de nivel înalt, care se numeşte „regiune critică”. Prin aceasta se urmăreşte, pe de
o parte, evidenţierea explicită în program a variabilelor partajate şi, pe de altă parte,
introducerea unei instrucţiuni speciale pentru accesul la aceste variabile.
Astfel, specificarea unei variabile partajate v se face printr-o declaraţie de forma
shared tip v;
iar accesul la variabila v este permis numai în interiorul construcţiei
region v do instr. 1; instr. 2; …. instr. n end;
La un moment dat un singur proces poate executa instrucţiunea compusă region
referitoare la o aceeaşi variabilă partajată. Mai exact, executarea instrucţiunii compuse region
v decurge astfel:
• dacă nici un alt proces nu se află în interiorul unei instrucţiuni region v atunci procesul
continuă executarea secvenţei instr.1; instr. 2; …. instr. n;
• dacă însă un alt proces execută deja o instrucţiune region v, procesul va fi blocat într-un
şir de aşteptare asociat variabilei v. Când un proces încheie o instrucţiune region v se
activează, dacă este cazul, unul din procesele care aşteaptă în şirul asociat.
Această construcţie asigură în mod automat excluderea mutuală între procese evitând
încadrarea explicită a regiunilor critice între primitive 𝑃 şi 𝑉. Este sarcina compilatorului ca
pentru o variabilă partajată să creeze un semafor binar, să încadreze regiunile critice între
primitivele P şi V şi să semnaleze ca eroare folosirea variabilei partajate în afara regiunilor
critice.
Pentru asigurarea sincronizării pe condiţie s-a propus o extindere a acestei construcţii,
numită „regiune critică condiţională”, de forma:

region v when 𝑏 do instr. 1; instr. 2; …. ; instr. n end;

în care 𝑏 este o expresie logică.


În expresia logică 𝑏, cu rol de gardă, care trebuie să fie adevărată pentru ca un proces să
poată pătrunde în regiunea critică, pot apărea pe lângă variabila v, sau componente ale ei, şi
variabile locale procesului. Procesele se exclud pe durata evaluării expresiei 𝑏 şi a executării
secvenţei de instrucţiuni, aşa cum este ilustrat printr-o reţea Petri în Fig. 1.
Un proces pus în aşteptare pentru că expresia 𝑏 este falsă va putea continua numai după
ce 𝑏 îşi schimbă valoarea. Procesul va fi reactivat după ce un alt proces execută instrucţiunea
region v (numai aşa variabilele de stare îşi pot schimba valoarea) pentru a-şi verifica din nou
condiţia necesară continuării execuţiei. Intervine deci o formă de aşteptare semiactivă.

1
Fig. 1 − Executarea regiunilor critice condiţionale.

În continuare se prezintă câteva exemple de folosire a regiunilor critice.

1. Problema „producători - consumatori”

Să reluăm problema tranferului de mesaje de la procese producător către procese


consumator prin intermediul unui buffer circular cu n locaţii. Structura buffer-ului este
prezentată în Fig. 2.

Fig. 2 – Structura buffer-ului.

Aşa cum se arată în figură, se introduce o variabilă de stare 𝑛𝑚 cu semnificaţia numărului


de mesaje nepreluate. Astfel, starea buffer-ului este specificată în mod explicit: dacă 𝑛𝑚 = 0
buffer-ul este gol, iar dacă 𝑛𝑚=n buffer-ul este plin. Prin urmare, se impune ca producătorii
să aibă acces la buffer când 𝑛𝑚 < 𝑛, iar consumatorii, când 𝑛𝑚 > 0.
Variabilele cursor l şi o asociate buffer-ului au următoarea semnificaţie:
• 𝑙 indică prima locaţie liberă în care se va depune următorul mesaj; variabila se
initializează cu 0 şi nu are semnificaţie când buffer-ul este plin;
• 𝑜 indică prima locaţie ocupată din care se va prelua următorul mesaj; variabila se
initializează cu 0 şi nu are semnificaţie când buffer-ul este gol.

2
Pentru varianta de control în care accesul la buffer este permis unui singur proces, se
impune ca buffer-ul T şi variabilele asociate l, o şi nm să fie incluse într-o singură structură,
partajată de către toate procesele. Secvenţa de program care descrie acest mecanism de
transfer este următoarea:

shared struct {
mesaj T [n];
int 𝑙 = 0;
int 𝑜 = 0;
int 𝑛𝑚 = 0;
} v;
cobegin
|| /* proces producător */ || /* proces consumator */
-------------- --------------
mesaj 𝑚; mesaj 𝑚;
-------------- --------------
#generează mesaj m ; region v when v.nm>0 do
region v when v.nm<n do m = v.T [v.o] ;
v.T [v.l] = m; v.o = (v.o+1) % n;
v.l = (v.l+1) % n; v.nm−−;
v.nm++; end;
end; #prelucrează mesaj m;
-------------- --------------
coend.
Se remarcă simplitatea şi claritatea secvenţei de program în acest caz.

Să realizăm în continuare un mecanism de acces la buffer în variantă îmbunătăţită, care să


permită ca o operaţie de depunere şi una de extragere să se poată face în paralel, dacă cele
două procese operează cu locaţii diferite (variabilele cursor 𝑙 şi 𝑜 au valori diferite).
Observaţii preliminară:
• Variabilele cursor 𝑙 şi 𝑜 sunt egale numai atunci când buffer-ul este plin sau este gol. În
aceste condiţii însă una din cele două categorii de procese nu pot accesa buffer-ul. Este
suficientă aşadar serializarea accesului la buffer pentru procese de acelaşi tip.
• Pentru a permite ca cele două operaţii să se poată face în paralel, se impune în mod necesar
ca buffer-ul 𝑇 să fie extras din structura partajată.
O primă încercare de rezolvare a problemei ar fi aşadar următoarea:
mesaj 𝑇 [𝑛];
shared int 𝑙 = 0; // variabilă partajată de procesele producător
shared int 𝑜 = 0; // variabilă partajată de procesele consumator
shared int 𝑛𝑚 = 0; // variabilă partajată de toate procesele
cobegin
|| /* proces producător */ || /* proces consumator */

3
mesaj 𝑚; mesaj 𝑚;
-------------- --------------
#generează mesaj 𝑚; region 𝑛𝑚 when 𝑛𝑚 > 0 do ;
region 𝑛𝑚 when 𝑛𝑚 < 𝑛 do ; region 𝑜 do
region l do m = T [o] ;
𝑇 [𝑙] = 𝑚; 𝑜 = (𝑜 + 1) % 𝑛;
𝑙 = (𝑙 + 1) % 𝑛; end;
end; ⊳
⊳ region 𝑛𝑚 do 𝑛𝑚 − −;
region 𝑛𝑚 do 𝑛𝑚 + +; #prelucrează mesajul m;
-------------- --------------

coend.

Regiunile critice „region l” şi „region o” realizează în mod corect serializarea pentru accesul
la buffer a proceselor producător, pe de o parte, şi a celor consumator, pe de altă parte. De
asemenea, se creează posibilitatea ca o operaţie de depunere şi una de extragere să se poată
face în paralel.
Sincronizarea pe condiţie, care să impiedice un proces producător să depună în buffer când
acesta este plin, sau ca un proces consumator să acceseze buffer-ul când acesta este gol, nu
mai este însă una corectă. Într-adevăr, să presupunem că 𝑛𝑚 = 𝑛 − 1 şi un proces producător
solicită accesul la buffer pentru depunerea unui nou mesaj. Accesul este permis şi operaţia
poate avea loc în mod corect. Dacă însă procesul este întrerupt (simbolul ⊳) înainte ca
actualizarea variabilei 𝑛𝑚 să aibă loc, atunci accesul la buffer va fi permis şi altui proces
producător, ceea ce nu mai este corect până când nu se creează o nouă locaţie liberă. Un
raţionament similar evidenţiază faptul că şi la procesele consumator poate apărea o eroare de
sincronizare pe condiţie de acest tip (de verificat!).
Eroarea semnalată a apărut datorită faptului că verificarea condiţiei de acces la buffer şi
actualizarea variabilei de stare 𝑛𝑚 se fac în structuri region nm diferite.
Pentru a depăşi acest neajuns, se încearcă o nouă variantă de sincronizare în care verificarea
condiţiei de acces la buffer şi actualizarea variabilei de stare 𝑛𝑚 să se facă în cadrul aceleiaşi
instrucţiuni region. Secvenţa de program ar fi următoarea:

// proces producător // proces consumator


-------------- --------------
#generează mesajul 𝑚; region 𝑛𝑚 when 𝑛𝑚 > 0 do 𝑛𝑚 − −;
region 𝑜 do
region 𝑛𝑚 when 𝑛𝑚 < 𝑛 do 𝑛𝑚 + +;
region l do ⊳
⊳ m = T [o] ;
𝑜 = (𝑜 + 1) % 𝑛;
𝑇 [𝑙] = 𝑚;
end;
𝑙 = (𝑙 + 1) % 𝑛;
end; #prelucrează mesajul m;
-------------- --------------
coend.

4
Din păcate, nici această soluţie nu este corectă. De exemplu, să presupunem că 𝑛𝑚 = 0 şi un
proces producător solicită accesul la buffer pentru depunerea unui nou mesaj. Accesul este
permis în mod firesc. Dacă însă procesul este întrerupt înainte ca operaţia de depunere să se
fi încheiat, iar un proces consumator solicită accesul la buffer pentru preluarea mesajului,
accesul va fi permis în mod greşit pe baza variabilei de stare 𝑛𝑚 care este 1. O eroare de
sincronizare pe condiţie poate apărea şi atunci când un proces consumator este întrerupt
înainte ca operaţia de extragere să se fi încheiat (de verificat!). Această încercare a eşuat
pentru că variabila de stare 𝑛𝑚 este actualizată în avans, înainte ca operaţia să aibă loc.
Cele două încercări eşuate demonstrază faptul că o soluţie de sincronizare pe condiţie bazată
pe o singură variabilă de stare (𝑛𝑚 în acest caz) nu este posibilă.
Să revenim aşadar la soluţia implementată cu semafoare, unde starea buffer-ului este
descrisă redundant prin numărul de locaţii libere (𝐿) şi prin numărul de locaţii ocupate cu
mesaje nepreluate (𝑂), şi să imităm rezolvarea de acolo. Mecanismul de sincronizare care
rezolvă corect accesul la buffer în varianta îmbunătăţită este prezentat în continuare.

mesaj 𝑇 [𝑛];
shared int 𝑙 = 0; // variabilă partajată de procesele producător
shared int 𝑜 = 0; // variabilă partajată de procesele consumator
shared int 𝐿 = 𝑛;
shared int 𝑂 = 0; // variabile partajate de toate procesele
cobegin

|| /* producător */ || /* consumator */
mesaj 𝑚; mesaj 𝑚;
-------------- --------------
#generează mesaj 𝑚; region 𝑂 when 𝑂 > 0 do 𝑂 − −;
// verificarea accesului cu rezervarea unui mesaj
region 𝐿 when 𝐿 > 0 do 𝐿 − − ;
// verificarea accesului cu rezervarea unei locaţii region 𝑜 do
m = T [o] ;
region l do
𝑜 = (𝑜 + 1) % 𝑛;
𝑇 [𝑙] = 𝑚;
end;
𝑙 = (𝑙 + 1)% 𝑛;
end; region 𝐿 do 𝐿 + +;
// relansarea unui eventual proces producător
region 𝑂 do 𝑂 + +; care aşteaptă o locaţie liberă
// relansarea unui eventual proces consumator
care aşteaptă un nou mesaj #prelucrează mesaj m;
-------------- --------------
coend.

Notă: Ca o comparaţie, putem să ne gândim cum funcţionează un hotel, care este tot o
structură partajată cu mai multe locaţii de acelaşi tip. Verificarea accesului cu rezervare din
secvenţa noastră este identică cu solicitarea de rezervare a unei camere. Dacă solicitarea poate
fi îndeplinită se rezervă o cameră, pe care nu o ocupăm însă atunci. Apoi camera se
disponibilizează după ce este eliberată efectiv.

5
Pentru sincronizarea pe condiţie se foloseşte şi o altă formă de regiune critică condiţională
în care verificarea condiţiei de continuare a executării se face după efectuarea secvenţei de
instrucţiuni din corpul construcţiei region.
region v do instr. 1; instr. 2; …; instr. n await b end;
Pentru a evidenţia utilitatea acestei noi forme de sincronizare pe condiţie se propune
următoarea problemă.

2. Partajarea unui fişier cu prioritate la scriere


Să considerăm un fişier partajat de către mai multe procese concurente. Ne propunem
realizarea unui mecanism de control privind accesul la fişier respectând următoarele condiţii
privind disciplina de acces:
• Scrierea în fişier se face prin excludere mutuală între procese;
• Citirea simultană din fişier este permisă pentru mai multe procese;
• Operaţiile de scriere în fişier au prioritate faţă de cele de citire pentru ca procesele
cititor să beneficieze de informații actualizate.

➢ Analiza detaliată a problemei


Pentru a impune ca solicitările de acces în scriere să se facă cu prioritate, este bine ca
procesele care aşteaptă eliberarea fişierului să fie blocate în cozi distincte, în funcţie de tipul
accesului, aşa cum este ilustrat în Fig. 3.

ss w
ca = 0

ca > 0

R
ss = 0
ca
ss > 0

Fig. 3 – Organizarea aşteptării pentru accesul la fişier

Semnificaţia variabilelor care intervin în figură este următoarea:


• 𝑠𝑠 – numărul solicitărilor de acces la fişier în scriere; o solicitare se consideră
rezolvată după închiderea fişierului accesat.
• 𝑐𝑎 – numărul proceselor care au acces la fişier în citire la un moment dat.
Pentru că accesul la fişier în scriere se face prin excludere mutuală între procese, se
recomandă ca operaţiile de lucru cu fişierul să fie incluse într-o construcţie region. În ceea ce
priveşte citirea însă, pentru a asigura accesul simultan pentru mai multe procese, operaţiile
de lucru cu fişierul trebuie să apară în afara oricărei construcţii region.
Dacă accesul la fişier în scriere nu este posibil, procesul trebuie blocat dar nu înainte de a
înregistra cererea prin incrementarea variabilei de stare 𝑠𝑠. Altfel, solicitările ulterioare de
acces la fişier în citire ar putea să fie acceptate înainte.

6
Variabila de stare 𝑠𝑠 este actualizată de procesele care solicită accesul la fişier în scriere şi
trebuie verificată de procesele care solicită accesul în citire. Similar, variabila de stare 𝑐𝑎 este
actualizată de procesele care au obţinut accesul la fişier în citire şi trebuie verificată de
procesele care solicită accesul în scriere. Pentru a putea fi folosite în cadrul aceleiaşi
instrucţiuni region cele două variabile trebuie reunite într-o singură structură partajată.

➢ Rezolvare cu regiuni critice


Pe baza elementelor menţionate anterior se realizeză un mecanism de control privind
accesul la fişier, aşa cum se prezintă în următoarea secvenţă de program.

shared struct {
int 𝑠𝑠 = 0;
int 𝑐𝑎 = 0;
} v;
shared int w;
cobegin
|| /* Proces 1 - acces în scriere */ || /* Proces 2 - acces în citire */
-------------- --------------
region 𝑣 do 𝑣. 𝑠𝑠 + +; await 𝑣. 𝑐𝑎 == 0 end; region 𝑣 when 𝑣. 𝑠𝑠 == 0 do 𝑣. 𝑐𝑎 + + end;
region w do # deschide fişier în citire
# deschide fişier cu opţiune de scriere # citeşte fişier
# actualizează fişier # închide fişier
# închide fişier
region 𝑣 do 𝑣. 𝑐𝑎 − −;
end;
--------------
region 𝑣 do 𝑣. 𝑠𝑠 − −;
--------------
coend.

Precizări suplimentare privind implementarea mecanismului de control:


1) Fizic, pentru cele două tipuri de solicitări de acces la fişier se formează o singură coadă
de aşteptare asociată structurii partajate v, şi nu două cum este ilustrat în figură. Dar cele
două tipuri de procese blocate sunt reactivate în condiţii diferite, ceea ce în fond e ca şi
cum ar fi şi fizic dispuse în două cozi de aşteptare distincte.
2) Procesele care solicită accesul la fişier în scriere şi au trecut de garda din cadrul
instrucţiunii region v formează o coadă de aşteptare asociată variabilei partajate w; de
aici procesele sunt reactivate pe rând pe măsura ce fişierul este eliberat. Accesul exlusiv
la fişier pentru operaţii de scriere este implementat aşadar în două trepte.
3) Pentru cereri de acelaşi tip accesul la fişier nu este garantat în ordinea solicitărilor.
Se remarcă totuşi simplitatea şi claritatea implementării mecanismului de control privind
accesul la fişier în comparaţie cu rezolvarea bazată pe semafoare.

7
STR Cursul 13 – partea I

Regiuni critice simple şi condiţionale - continuare

1. Partajarea unui fişier cu acces în ordinea solicitărilor


Să reluăm problema partajării unui fişier de către mai multe procese concurente impunând
de această dată ca accesul la fişier să se facă în ordinea solicitărilor.

➢ Analiza detaliată a problemei


Pentru reflectarea la nivelul aplicaţiei a stării fişierului la un moment dat, se foloseşte o
variabilă f cu următoarea semnificaţie:
0 → fişier închis (disponibil)
𝑓 = { −1 → fişier deschis în scriere
> 0 → fişier deschis în citire

Pentru a asigura îndeplinirea condiţiei privind accesul la fişier în ordinea solicitărilor, se


impune ca atunci când fişierul nu este disponibil procesele să fie blocate într-o coadă de
aşteptare comună, așa cum este ilustrat în figura următoare. Reamintim că după verificarea
accesului la fișier în scriere (situație ilustrată prin simbolul ∘), poarta A se închide, în timp ce
după verificarea accesului în citire (simbolul •), poarta A trebuie să rămână deschisă. În plus,
pentru accesul la fişier în scriere decizia se ia în două trepte, aşa cum s-a aplicat şi în cazul
mecanismului de control bazat pe semafoare.

𝑓 = −1
A A
sau

𝑓 >0
=1

Figura 4 – Accesul la fişier cu decizie în două trepte pentru scriere.

➢ Rezolvare
Pe baza elementelor menţionate anterior, se încearcă realizarea un mecanism de control
privind accesul la fişier conform următoarei secvenţe de program. De remarcat că la scriere,
pentru asigurarea accesului exclusiv la fișier, operațiile de lucru cu fișierul sunt incluse în
corpul instrucțiunii 𝑟𝑒𝑔𝑖𝑜𝑛 𝑓, în timp ce operațiile de lucru cu fișierul în citire sunt în mod
necesar în afara oricărei instrucțiuni 𝑟𝑒𝑔𝑖𝑜𝑛.

shared int A = deschis; // A ∈ { închis, deschis}


shared int 𝑓 = 0;

1
cobegin
|| /* Proces 1 - acces în scriere */ || /* Proces 2 - acces în citire */

--------------------- ---------------------
region 𝐴 when 𝐴 == deschis do A = închis; end; region 𝐴 when 𝐴 == deschis do ; end;

region f when 𝑓 == 0 do
𝑓 = −1; region f when 𝑓 ≥ 0 do 𝑓 + +;
# deschide fişier cu opţiune de scriere # deschide fişier în citire
# actualizează fişier # citeşte fişier
# închide fişier # închide fişier
𝑓 =0;
region f do 𝑓 − −;
end;
---------------------
region 𝐴 do 𝐴 = deschis ; end;
---------------------
coend.
La această primă variantă, există însă un neajuns. Să considerăm situația în care fișierul
este liber (𝑓 = 0) și un proces care solicită accesul în citire este întrerupt între cele două
instrucțiuni 𝑟𝑒𝑔𝑖𝑜𝑛 , așa cum este ilustrat în figură prin simbolul ⊳ . Dacă următoarea
solicitare este pentru scrierea în fișier, aceasta va fi acceptată înaintea cererii anterioare de
acces în citire, încălcându-se astfel regula accesului în ordinea solicitărilor. Mecanismul de
control privind accesul la fișier în citire descris în următoarea secvență de program rezolvă
acest neajuns.

shared int A = deschis; // A ∈ { închis, deschis}


shared int 𝑓 = 0;
cobegin
|| /* Proces 1 - acces în scriere */ || /* Proces 2 - acces în citire */
--------------------- ---------------------
region 𝐴 when 𝐴 == deschis do region 𝐴 when 𝐴 == deschis do
A = închis; A = închis;
end; end;
region f when 𝑓 == 0 do region f when 𝑓 ≥ 0 do 𝑓 + +; end;
𝑓 = −1; region 𝐴 do 𝐴 = deschis; end;
# deschide fişier cu opţiune de scriere
# actualizează fişier # deschide fişier în citire
# închide fişier # citeşte fişier
𝑓 =0; # închide fişier
end; region 𝑓 do 𝑓 − −; end;
region 𝐴 do 𝐴 = deschis ; end; ---------------------
--------------------- coend.

2
2. Concluzii privind regiunile critice
Faţă de semafoare, regiunile critice au marcat un salt deosebit în ceea ce priveşte creşterea
simplităţii şi clarităţii programelor. Variabilele partajate sunt specificate explicit, iar
excluderea mutuală între procese se realizează în mod automat. Încercarea de accesare a unei
variabile partajate în afara regiunii critice corespunzătoare este semnalată ca eroare de către
compilator. De asemenea, sincronizarea pe condiţie este clar evidenţiată în program.
Cu toate acestea, regiunile critice au un mare neajuns, acela că sincronizarea pe condiţie se
realizează prin aşteptare semiactivă. Aşa cum este evidenţiat şi în reţeaua Petri, procesele sunt
reactivate în mod repetat pentru a-şi verifica condiţia necesară continuării execuţiei.
În ceea ce priveşte structura programului, regiunile critice sunt dispersate în interiorul
proceselor, ceea ce face ca pentru verificarea corectitudinii codul sursă să fie parcurs în
întregime.

3
STR Cursul 13 – partea a II-a

Sincronizarea proceselor prin intermediul structurii de monitor

Odată cu dezvoltarea ingineriei programării în direcţia modularizării şi a apariţiei


conceptului de clasă, s-a pus problema reunirii tuturor variabilelor partajate şi a
operaţiilor de lucru cu acestea într-o structură unică care s-a numit Monitor. Regiunile
critice sunt aşadar extrase din interiorul proceselor şi introduse în monitor sub formă de
proceduri sau metode. Singura posibilitate de acces la variabilele partajate o constituie
apelul unei proceduri de monitor.
Excluderea mutuală între procese la folosirea variabilelor partajate se realizează în mod
implicit întrucât monitorul este el însuşi o resursă critică, în sensul că un singur proces
poate beneficia de serviciile lui la un moment dat. Dacă la apelul unei proceduri de
monitor un alt proces execută deja o procedură din cadrul monitorului, acesta va fi blocat
într-o coadă de aşteptare dedicată accesului la monitor. Procesele din această coadă de
aşteptare vor fi reactivate pe rând, în ordinea solicitărilor, pe măsură ce monitorul este
eliberat.
Dacă excluderea mutuală între procese se realizează în mod implicit, transparent la
nivelul programului, sincronizarea pe condiţie se face cu mijloace gestionate în mod
explicit de către programator. În timp au fost propuse mai multe mecanisme de
sincronizare pe condiţie asociate structurii de monitor.
Să analizăm mai întâi varianta propusă de Tony Hoare.

I. Mecanism de sincronizare pe condiţie bazat pe operaţiile 𝐰𝐚𝐢𝐭 şi 𝐬𝐢𝐠𝐧𝐚𝐥

La varianta propusă de Hoare, pentru sincronizarea pe condiţie în cadrul structurii de


monitor se folosesc variabile speciale de tip 𝑐𝑜𝑛𝑑𝑖𝑡𝑖𝑜𝑛 şi operaţiile primitive 𝑤𝑎𝑖𝑡 şi 𝑠𝑖𝑔𝑛𝑎𝑙,
aşa cum se exemplifică în următoarea secvenţă de program.

Monitor M;
var
condition 𝑥;
boolean 𝑐 ;
procedure 𝑝1; procedure 𝑝2 ;
begin begin
……… ………
if not 𝑐 then 𝑤𝑎𝑖𝑡(𝑥); if 𝑐 then 𝑠𝑖𝑔𝑛𝑎𝑙(𝑥);
……… ………
end; end;

begin
𝑐 ∶= 𝑓𝑎𝑙𝑠𝑒;
end. // monitor M
1
Sincronizarea pe condiţie între două procese este ilustrată în figura următoare.

Fig. 1 – Sincronizarea între procese prin intermediul operaţiilor 𝑤𝑎𝑖𝑡 şi 𝑠𝑖𝑔𝑛𝑎𝑙.

Operaţiile evidenţiate prin săgeţi şi numerotate în figură au următoarea semnificaţie:


1 – Primul proces accesează monitorul pentru a executa procedura 𝑝1 ;
2 – Procesul execută operaţia 𝑤𝑎𝑖𝑡 (acesta este blocat iar monitorul este eliberat);
3 – Al doilea proces accesează monitorul pentru a executa procedura 𝑝2 ;
4 – Procesul execută operaţia 𝑠𝑖𝑔𝑛𝑎𝑙 (procesul este blocat iar monitorul, eliberat);
5 – Primul proces este reactivat pentru continuarea procedurii întrerupte 𝑝1;
6 – Procesul termină procedura 𝑝1 şi eliberează monitorul;
7 – Al doilea proces este reactivat pentru continuarea procedurii întrerupte 𝑝2 ;
8 – Procesul termină procedura 𝑝2 şi eliberează monitorul.
Mai precis, dacă în timpul executării unei proceduri de monitor, un proces găseşte condiţia
necesară continuării execuţiei ca fiind neîndeplinită (condiţia 𝑐 ), atunci cu operaţia
𝑤𝑎𝑖𝑡(𝑥) se autosuspendă şi este blocat în coada de aşteptare a variabilei 𝑥 de tip condition.
Monitorul este astfel eliberat. Procesul rămâne blocat până când un alt proces îl va relansa
prin intermediul unei operaţii 𝑠𝑖𝑔𝑛𝑎𝑙(𝑥). Această operaţie decurge astfel:
- Dacă în coada de aşteptare a variabilei 𝑥 nu este niciun proces blocat, operaţia 𝑠𝑖𝑔𝑛𝑎𝑙
nu are niciun efect;

2
- Dacă, însă, în coada de aşteptare sunt procese blocate, atunci procesul curent se
auto-suspendă temporar şi este blocat în coada de aşteptare dedicată proceselor care
execută 𝑠𝑖𝑔𝑛𝑎𝑙.
- Unul din procesele blocate în coada de aşteptare dedicată variabile 𝑥 este reactivat
pentru a-şi continua procedura de monitor întreruptă cu următoarea instrucţiune de
după 𝑤𝑎𝑖𝑡(𝑥).
Prin urmare, sincronizarea pe condiţie în cadrul structurii de monitor implică formarea
mai multor cozi de aşteptare, şi anume:
- O coadă de aşteptare dedicată proceselor care solicită accesul la monitor; procesele
sunt reactivate în ordinea solicitărilor pe măsură ce monitorul este eliberat.
- Câte o coadă de aşteptare pentru fiecare variabilă 𝑥 de tip condition – în aceste cozi
sunt blocate procesele pentru care nu sunt îndeplinite condiţiile de continuare a
executării lor.
- O coadă de aşteptare dedicată proceselor care se autosuspendă temporat prin
intermediul operaţiei signal; aceste procese au prioritate la reactivare faţă de alte
procese care nu au primit încă acceptul de acces la monitor.
În continuare se exemplifică sincronizarea între procese prin intermediul acestui
mecanism.

1. Problema „producători - consumatori”


Să reluăm problema tranferului de mesaje de la procese producător către procese
consumator prin intermediul unui buffer circular cu n locaţii. Structura buffer-ului este
prezentată în Fig. 2.

Fig. 2 – Structura buffer-ului şi variabilele asociate.

Aşa cum se arată în figură, se foloseşte o variabilă de stare 𝑛𝑚 care reflectă numărul de
mesaje nepreluate. Prin urmare, se poate impune ca producătorii să aibă acces la buffer
când 𝑛𝑚 < 𝑛, iar consumatorii, când 𝑛𝑚 > 0. Variabilele cursor l şi o au semnificaţia
cunoscută.
cobegin
|| /* proces producător */ || /* proces consumator */
---------------- ----------------
mesaj 𝑚; mesaj 𝑚;
#generează mesaj m; M.extrage(&𝑚);
M.depune(𝑚); #prelucrează mesaj m;
---------------- ----------------
coend.

3
Monitor M;
mesaj 𝐵[𝑛];
int 𝑙, 𝑜, 𝑛𝑚;
condition 𝑃, 𝐶;
procedure 𝑑𝑒𝑝𝑢𝑛𝑒 (mesaj 𝑚); procedure 𝑒𝑥𝑡𝑟𝑎𝑔𝑒 (mesaj ∗ 𝑝𝑚);
begin begin
if 𝑛𝑚 == 𝑛 then 𝑤𝑎𝑖𝑡(𝑃); if 𝑛𝑚 == 0 then 𝑤𝑎𝑖𝑡(𝐶);
𝐵 [𝑙] = 𝑚; ∗ 𝑝𝑚 = 𝐵 [𝑜] ;
𝑙 = (𝑙 + 1) % 𝑛; 𝑜 = (𝑜 + 1) % 𝑛;
𝑛𝑚 + +; 𝑛𝑚 − −;
𝑠𝑖𝑔𝑛𝑎𝑙(𝐶); 𝑠𝑖𝑔𝑛𝑎𝑙(𝑃);
end end

begin
𝑛𝑚 = 0;
𝑙 = 0;
𝑜 = 0;
end. // Monitor M

Claritatea implementării mecanismului de control privind accesul la buffer este


evidentă. Totuşi, cu acest exemplu se poate evidenţia şi un neajuns al structurii de monitor.
Varianta îmbunătăţită, de relaxare a sincronizării între procese, care să permită ca o
operaţie de depunere şi una de extragere să se desfăşoare în paralel, nu mai este posibilă în
acest caz, datorită folosirii monitorului prin excludere mutuală între procese. Pentru astfel
de îmbunătăţiri sau de optimizări, monitorul se dovedeşte a fi o structură mai rigidă.
Structura de monitor conţine şi o operaţie de tip 𝑠𝑖𝑔𝑛𝑎𝑙𝐴𝑙𝑙(𝑥) prin care sunt deblocate
toate procesele din coada de aşteptare asociată variabilei 𝑥 de tip 𝑐𝑜𝑛𝑑𝑖𝑡𝑖𝑜𝑛. Procesele îşi
vor continua pe rând procedura de monitor întreruptă pe măsură ce monitorul este
eliberat. În fapt, procesele blocate sunt transferate din coada de aşteptare asociată
variabilei 𝑥 în fruntea cozii de aşteptare pentru accesul la monitor. Aşadar, aceste procese
au prioritate faţă de procesele care nu au primit încă dreptul de acces la monitor.
Pentru a evidenţia utilitatea unei astfel de operaţii, să urmărim soluţia privind controlul
accesului la un fişier partajat din exemplul următor.

2. Partajarea unui fişier cu prioritate la scriere

Să reluăm problema controlului privind accesul la un fişier partajat de către mai multe
procese concurente, în care operaţiile de scriere în fişier au prioritate faţă de cele de citire.
Reamintim că scrierea în fişier se face prin excludere mutuală între procese, iar citirea
simultană din fişier este permisă pentru mai multe procese.
Pentru a impune ca solicitările de acces în scriere să se facă cu prioritate, procesele care
trebuie să aştepte accesul la fişier sunt dispuse la coadă în funcţie de tipul accesului.
4
𝑠𝑠 S
𝑐𝑎 = 0

𝑐𝑎 > 0

C
𝑠𝑠 = 0
ca
𝑠𝑠 > 0

Fig. 3 – Organizarea aşteptării pentru accesul la fişier, cu prioritate la scriere

Semnificaţia variabilelor de stare din figură este următoarea:


• 𝑠𝑠 – numărul solicitărilor de acces la fişier în scriere; o solicitare se consideră
rezolvată după închiderea fişierului accesat.
• 𝑐𝑎 – numărul proceselor care au acces la fişier în citire la un momnet dat.

Secvenţa de program şi structura de monitor care evidenţiază această implementare este


următoarea:

cobegin
|| /* proces 1 */ || /* proces 2 */

/* acces la fişier în scriere */ /* acces la fişier în citire */


-------------- --------------
M.accesScriere; M.accesCitire;
# deschide fişier cu opţiune de scriere # deschide fişier în citire
# actualizează fişier # citeşte fişier
# închide fişier # închide fişier
M.sfarsitScriere; M. sfarsitCitire;
--------------
--------------
coend.

Monitor M;
int 𝑠𝑠, 𝑐𝑎;
condition 𝑆, 𝑅;

procedure 𝑎𝑐𝑐𝑒𝑠𝑆𝑐𝑟𝑖𝑒𝑟𝑒(); procedure 𝑎𝑐𝑐𝑒𝑠𝐶𝑖𝑡𝑖𝑟𝑒();


begin begin
𝑠𝑠 + +; if 𝑠𝑠 > 0 then 𝑤𝑎𝑖𝑡(𝐶);
if 𝑠𝑠 > 1 || 𝑐𝑎 > 0 then 𝑤𝑎𝑖𝑡(𝑆); 𝑐𝑎 + +;
end end

5
procedure 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝑆𝑐𝑟𝑖𝑒𝑟𝑒(); procedure 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝐶𝑖𝑡𝑖𝑟𝑒();
begin begin
𝑠𝑠 − −; 𝑐𝑎 − −;
if 𝑠𝑠 > 0 then 𝑠𝑖𝑔𝑛𝑎𝑙(𝑆); if 𝑐𝑎 == 0 then 𝑠𝑖𝑔𝑛𝑎𝑙(𝑆);
else 𝑠𝑖𝑔𝑛𝑎𝑙𝐴𝑙𝑙(𝐶); end
end

begin
𝑠𝑠 = 0;
𝑐𝑎 = 0;
end. // Monitor M

Cu privire la sicronizarea proceselor prin intermediul structurii de monitor să semnalăm


următorul aspect. La varianta de sicronizare pe condiţie bazată pe operaţiile 𝑤𝑎𝑖𝑡(𝑥) şi
𝑠𝑖𝑔𝑛𝑎𝑙(𝑥), principiul accesului exclusiv la variabilele partajate nu este respectat pe deplin,
ci doar pe durata cât procesul este activ. Într-adevăr, la un moment dat pot ajunge cu firul
de execuţie în interiorul monitorului mai multe procese, dintre care însă numai unul este
activ. Problema care apare se referă la procesele care s-au autosuspendat temporar
executând 𝑠𝑖𝑔𝑛𝑎𝑙, deoarece acestea nu mai pot conta cu certitudine la reluare pe valoarea
variabilelor de monitor din momentul întreruperii. Din acest motiv, se recomandă ca o
operaţie 𝑠𝑖𝑔𝑛𝑎𝑙 să se apeleze la sfârşitul procedurii de monitor. În exemplele prezentate
până acum această recomandare a fost respectată.
Alte mecanisme de sincronizare pe condiţie respectă acest principiu, dar apar însă
probeme noi. Să analizăm în continuare mecanismul de sincronizare pe condiţie propus de
Brinch-Hansen şi implementat în prezent în Jawa, de exemplu.

6
STR Cursul 14

Sincronizarea proceselor prin intermediul structurii de monitor -


continuare

II. Mecanism de sincronizare pe condiţie bazat pe operaţiile wait şi 𝒏𝒐𝒕𝒊𝒇𝒚


Pentru sincronizarea pe condiţie în cadrul structurii de monitor, Brinch-Hansen a propus
(cam în acelaşi timp cu Hoare) un alt mecanism, bazat tot pe variabile speciale de tip
𝑐𝑜𝑛𝑑𝑖𝑡𝑖𝑜𝑛, dar la care se folosesc două operaţii primitive, 𝑤𝑎𝑖𝑡 şi 𝑛𝑜𝑡𝑖𝑓𝑦, ce respectă întru
totul condiţia de acces exclusiv la variabilele partajate. Efectul operaţiei 𝑤𝑎𝑖𝑡(𝑥) este cel
cunoscut: procesul curent se autosuspendă şi este blocat în coada de aşteptare asociată
variabilei 𝑥 iar monitorul este eliberat. Operaţia 𝑛𝑜𝑡𝑖𝑓𝑦(𝑥) diferă însă de operaţia 𝑠𝑖𝑔𝑛𝑎𝑙(𝑥).
Mai precis, prin executarea operaţiei 𝑛𝑜𝑡𝑖𝑓𝑦(𝑥) se transmite “o notificare” privind
deblocarea unui proces blocat în coada de aşteptare a variabilei 𝑥 (de tip condition), dar
monitoul nu este eliberat până la terminarea procedurii în curs. Dacă în coada de aşteptare
a variabilei 𝑥 nu sunt procese blocate, operaţia 𝑛𝑜𝑡𝑖𝑓𝑦(𝑥) nu are niciun efect. La acest
mecanism se formează doar două tipuri de cozi de aşteptare: coada de aşteptare primară
pentru accesul la monitor şi câte o coadă în care să fie blocate procese ce aşteaptă
îndeplinirea unei condiţii necesare continuării lor pentru fiecare variabilă de tip condition.
Figura următoare ilustrează acest mecanism de sincronizare.

Entry queue

1 3

Monitor
Wait
queue Variabile partajate

2
Procedura 𝑝1
6

Procedura 𝑝2 4

7 5

Fig. 4 – Sincronizarea între procese prin intermediul operaţiilor 𝑤𝑎𝑖𝑡 şi 𝑛𝑜𝑡𝑖𝑓𝑦.

1
Evenimentele evidenţiate în figură prin săgeţi numerotate au următoarea semnificaţie:
1 – Primul proces accesează monitorul şi începe executarea procedurii 𝑝1 ;
2 – Procesul se autosuspendă executând operaţia 𝑤𝑎𝑖𝑡 şi eliberează monitorul;
3 – Al doilea proces accesează monitorul şi începe executarea procedurii 𝑝2 ;
4 – Procesul execută operaţia 𝑛𝑜𝑡𝑖𝑓𝑦 dând astfel un semnal de îndeplinire a condiţiei
proceselor blocate în acest scop.
5 – Procesul termină procedura 𝑝2 şi eliberează monitorul;
6 – Procesul blocat este reactivat pentru continuarea procedurii 𝑝1 din punctul
întrerupt;
7 – Procesul termină procedura 𝑝1 şi eliberează monitorul.

Cu operaţia 𝑛𝑜𝑡𝑖𝑓𝑦(𝑥), principiul accesului exclusiv la variabilele partajate este garantat,


dar apare însă o problemă nouă, legată de procesul reactivat, care nu poate conta cu
certitudine pe îndeplinirea condiţiei aşteptate atunci când ajunge să execute procedura de
monitor întreruptă.
Ca urmare a acestui aspect, se recomandă includerea instrucţiunii 𝑤𝑎𝑖𝑡(𝑥) într-o buclă
while de forma:
while not condiţie do 𝑤𝑎𝑖𝑡(𝑥) end;
Deşi corectă, această soluţie artificială afectează întrucâtva claritatea programului. Dacă
toate operaţiile 𝑛𝑜𝑡𝑖𝑓𝑦(𝑥) apar la sfârşitul procedurii de monitor, includerea instrucţiunii
𝑤𝑎𝑖𝑡(𝑥) într-o buclă while nu se mai justifică.
Pentru exemplificarea acestui mecanism de sincronizare între procese prin intermediul
structurii de monitor, să reluăm o problemă de partajare a unui fişier de către mai multe
procese concurente.

3. Partajarea unui fişier cu priorităţi adaptive

Să reluăm problema controlului privind accesul la un fişier partajat de către mai multe
procese concurente. Specificaţiile privind accesul la fişier sunt următoarele:
• Scrierea în fişier se face prin excludere mutuală între procese;
• Citirea simultană din fişier este permisă pentru oricâte procese;
• De regulă, procesele care solicită accesul la fişier în scriere sunt acceptate cu prioritate,
dar atunci când numărul proceselor blocate pentru accesul la fişier în citire este mare
(de exemplu, ≥ 4) se acordă prioritate acestora.

➢ Analiza detaliată a problemei


Această disciplină de acces cu priorităţi adaptive asigură condiţia ca datele cele mai noi
să fie înregistrate în fişier cât mai repede. Totodată, disciplina conduce la o soluţie de
compromis prin care se evită întârzierea excesivă pentru accesul la fişier în citire.

2
Aşa cum am procedat şi la 𝑅𝑒𝑔𝑖𝑢𝑛𝑖 𝑐𝑟𝑖𝑡𝑖𝑐𝑒, pentru reflectarea la nivelul aplicaţiei a stării
fişierului la un moment dat, se foloseşte o variabilă f cu următoarea semnificaţie:

0 → fişier închis (disponibil)


𝑓 = { −1 → fişier deschis în scriere
> 0 → fişier deschis în citire
Pentru a impune regula de priorităţi specificată, procesele care trebuie să aştepte accesul
la fişier sunt dispuse în cozi distincte, în funcţie de tipul accesului, aşa cum se prezintă în
figura următoare.

ss 𝑆
𝑓 = −1

sau

sc 𝐶
𝑓 >0
=1

Fig. 5 – Organizarea aşteptării pentru accesul la fişier cu priorităţi adaptive.

Variabilelor de stare 𝑠𝑠 şi 𝑠𝑐 reflectă numărul solicitărilor de acces la fişier în scriere şi


respectiv, în citire, blocate în aşteptarea eliberării fişierului. La deschiderea fişierului
solicitarea se consideră încheiată.
Regula de prioritate specificată în enunţul problemei trebuie interpretată astfel:
(1) prioritatea acordată la scriere impune ca atât timp cât sunt procese în aşteptare pentru
accesul la fişier în scriere, alte solicitări pentru accesul la fişier să fie de asemenea blocate;
(2) după eliberarea fişierului de către un proces, pentru relansarea altor procese se ţine cont
de starea fişierului şi de numărul solicitărilor blocate pentru cele două tipuri de operaţii;
dacă numărul proceselor blocate pentru accesul la fişier în citire este ≥ 4 se acordă prioritate
acestora; altfel, se acordă prioritate solicitărilor de acces în scriere.
(3) pentru operaţii de acelaşi tip se impune accesul la fişier în ordinea solicitărilor.

În continuare se prezintă structura de monitor pentru controlul accesului la fişier în cele


două variante, cu operaţii de tip notify şi respectiv, de tip signal, pentru a evidenţia mai bine
diferenţa dintre cele două mecanisme de sincronizare.

➢ Varianta de monitor bazată pe operaţiile wait şi notify

Monitor M1;
var
int 𝑓, 𝑠𝑠, 𝑠𝑐; % variabile partajate
condition 𝑆, 𝐶;

3
procedure 𝑎𝑐𝑐𝑒𝑠𝑆𝑐𝑟𝑖𝑒𝑟𝑒(); procedure 𝑎𝑐𝑐𝑒𝑠𝐶𝑖𝑡𝑖𝑟𝑒();
{ {
𝑠𝑠 + +; 𝑠𝑐 + +;
if (𝑓 ! = 0) 𝑤𝑎𝑖𝑡(𝑆); if (𝑓 == −1 ∥ 𝑠𝑠 >0) 𝑤𝑎𝑖𝑡(𝐶);
𝑠𝑠 − −; 𝑠𝑐 − −;
𝑓 = −1; 𝑓 + +;
} }

procedure 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝑆𝑐𝑟𝑖𝑒𝑟𝑒(); procedure 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝐶𝑖𝑡𝑖𝑟𝑒();


{ {
int 𝑖; % variabilă locală int 𝑖; % variabilă locală
𝑓 = 0; 𝑓 − −;
if (! 𝑠𝑠 && 𝑠𝑐 > 0) 𝑛𝑜𝑡𝑖𝑓𝑦𝐴𝑙𝑙(𝐶); if (! 𝑓 && 𝑠𝑠 > 0 && 𝑠𝑐 < 4) 𝑛𝑜𝑡𝑖𝑓𝑦(𝑆);
else if (𝑠𝑠 > 0 && 𝑠𝑐 < 4) 𝑛𝑜𝑡𝑖𝑓𝑦(𝑆); else if (𝑠𝑐 ≥ 4) {
else if (𝑠𝑠 > 0 && 𝑠𝑐 ≥ 4) { for(𝑖 = 1; 𝑖 ≤ 𝑠𝑐 − 3; 𝑖 + +) {
for(𝑖 = 1; 𝑖 ≤ 𝑠𝑐 − 3; 𝑖 + +) { 𝑛𝑜𝑡𝑖𝑓𝑦(𝐶);
𝑛𝑜𝑡𝑖𝑓𝑦(𝐶); }
} } % 𝑒𝑛𝑑 − 𝑖𝑓
} % 𝑒𝑛𝑑 − 𝑖𝑓
} % 𝑒𝑛𝑑 − 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝐶𝑖𝑡𝑖𝑟𝑒
} % 𝑒𝑛𝑑 − 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝑆𝑐𝑟𝑖𝑒𝑟𝑒

begin % iniţializarea variabilelor partajate


𝑓 = 0; 𝑠𝑠 = 0; 𝑠𝑐 = 0;
end. // Monitor M1

Observaţie:
În 𝑎𝑐𝑐𝑒𝑠𝐶𝑖𝑡𝑖𝑟𝑒 varianta cu while este greşită! % while (𝑓 == −1 ∥ 𝑠𝑠 >0) 𝑤𝑎𝑖𝑡(𝐶);

➢ Varianta de monitor bazată pe operaţiile wait şi signal

Monitor M2;
var
int 𝑓, 𝑠𝑠, 𝑠𝑐; % variabile partajate
condition 𝑆, 𝐶;
procedure 𝑎𝑐𝑐𝑒𝑠𝑆𝑐𝑟𝑖𝑒𝑟𝑒(); procedure 𝑎𝑐𝑐𝑒𝑠𝐶𝑖𝑡𝑖𝑟𝑒();
{ {
𝑠𝑠 + +; 𝑠𝑐 + +;
if (𝑓 ! = 0) 𝑤𝑎𝑖𝑡(𝑆); if (𝑓 == −1 ∥ 𝑠𝑠 >0) 𝑤𝑎𝑖𝑡(𝐶);
𝑠𝑠 − −; 𝑠𝑐 − −;
𝑓 = −1; 𝑓 + +;
} }

4
procedure 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝑆𝑐𝑟𝑖𝑒𝑟𝑒(); procedure 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝐶𝑖𝑡𝑖𝑟𝑒();
{ {
int 𝑖, 𝑛𝑟; % variabile locale int 𝑖, 𝑛𝑟; % variabile locale

𝑓 = 0; 𝑓 − −;
if (! 𝑠𝑠 && 𝑠𝑐 > 0) 𝑠𝑖𝑔𝑛𝑎𝑙𝐴𝑙𝑙(𝐶); if (! 𝑓 && 𝑠𝑠 > 0 && 𝑠𝑐 < 4) 𝑠𝑖𝑔𝑛𝑎𝑙(𝑆);
else if (𝑠𝑠 > 0 && 𝑠𝑐 < 4) 𝑠𝑖𝑔𝑛𝑎𝑙(𝑆); else if (𝑠𝑐 ≥ 4) {
else if (𝑠𝑠 > 0 && 𝑠𝑐 ≥ 4) { 𝑛𝑟 = 𝑠𝑐 − 3;
/* variantă greşită (!) for(𝑖 = 1; 𝑖 ≤ 𝑛𝑟; 𝑖 + +) {
for(𝑖 = 1; 𝑖 ≤ 𝑠𝑐 − 3; 𝑖 + +) { 𝑠𝑖𝑔𝑛𝑎𝑙(𝐶);
𝑠𝑖𝑔𝑛𝑎𝑙(𝐶); }
} /* sau, tot bine
procesele relansate decrementează
while (𝑠𝑐 ≥ 4) 𝑠𝑖𝑔𝑛𝑎𝑙(𝐶); */
variabila 𝑠𝑐, modificându-se astfel
numărul de procese relansate */ /* la varianta cu 𝑛𝑜𝑡𝑖𝑓𝑦 soluţia ar fi
profund greşită ->buclă infinită */
𝑛𝑟 = 𝑠𝑐 − 3;
for(𝑖 = 1; 𝑖 ≤ 𝑛𝑟; 𝑖 + +) { } % 𝑒𝑛𝑑 − 𝑖𝑓
𝑠𝑖𝑔𝑛𝑎𝑙(𝐶); } % 𝑒𝑛𝑑 − 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝐶𝑖𝑡𝑖𝑟𝑒
}
} % 𝑒𝑛𝑑 − 𝑖𝑓
} % 𝑒𝑛𝑑 − 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝑆𝑐𝑟𝑖𝑒𝑟𝑒

begin % iniţializarea variabilelor partajate


𝑓 = 0, 𝑠𝑠 = 0, 𝑠𝑐 = 0;
end. // Monitor M2

4. Partajarea unui fişier cu acces în ordinea solicitărilor

Să considerăm problema controlului privind accesul la un fişier partajat de către mai


multe procese concurente, în condiţiile în care se impune în mod imperativ ca accesul la
fişier să se facă în ordinea solicitărilor. Reamintim că scrierea în fişier se face prin excludere
mutuală între procese, iar citirea simultană din fişier este permisă pentru mai multe procese.

➢ Analiza detaliată a problemei

Pentru a impune ca accesul să se facă în ordinea solicitărilor, procesele care trebuie să


aşteapte ca fişierul să devină disponibil sunt dispuse într-o coadă primară comună.
La primirea unei solicitări de acces la fişier, pe baza acestei variabile de stare cunoscute
𝑓 se poate decide uşor, în cadrul monitorului, dacă cererea poate fi acceptată sau nu.
Mai dificil de stabilit ce trebuie făcut este la schimbarea de stare a fişierului, după
încheierea unei operaţii de scriere sau de citire. Mai precis, când fişierul devine disponibil
după o scriere, de exemplu, ar trebui deblocat un singur proces dacă acesta solicită accesul

5
în scriere, şi unul sau mai multe procese consecutive (relansare în grup) dacă acestea solicită
accesul în citire. Dar, cu privire la o coadă de aşteptare asociată unei variabile 𝑥 de tip
condition nu cunoaştem decât dacă aceasta conţine sau nu procese blocate. În acest scop se
poate apela o funcţie de tip 𝑞𝑢𝑒𝑢𝑒(𝑥) sau 𝑒𝑚𝑝𝑡𝑦(𝑥) a căror semnificaţie este evidentă.
Pe de altă parte, la soluţia bazată pe semafoare sau pe regiuni critice, s-a arătat că pentru
accesul la fişier este necesară o decizie în două trepte. Vom adopta şi aici acest model,
impunând două trepte de decizie, 𝐴1 şi 𝐴2 , aşa cum este ilustrat în figura următoare.

𝑓 = −1
𝐴1 𝐴2
sau

𝑓 >0
=1

Fig. 6 – Accesul la fişier cu decizie în două trepte.

În acest mod, la eliberarea fişierului, este deblocat un singur proces, cel care aşteaptă la
poarta de acces 𝐴2 , urmând ca acesta să relanseze la rândul său un proces din coada de
aşteptare primară (din spatele porţii de acces 𝐴1 ) . Când în coada primară sunt cereri
consecutive care solicită accesul în citire, acestea sunt deblocate unul câte unul, fiind practic
relansate în grup. După acestea, procesul care solicită accesul la fişier în scriere va rămâne
blocat la poarta de acces 𝐴2 .
Secvenţa de program care priveşte lucrul cu fişierul şi structura de monitor (numit 𝑀𝐶𝐹)
pentru controlul accesului la fişier sunt prezentate în continuare.

cobegin
|| /* proces 1 */ || /* proces 2 */

/* acces la fişier în scriere */ /* acces la fişier în citire */


-------------- --------------
𝑀𝐶𝐹. 𝑎𝑐𝑐𝑒𝑠𝑆𝑐𝑟𝑖𝑒𝑟𝑒; 𝑀𝐶𝐹. 𝑎𝑐𝑐𝑒𝑠𝐶𝑖𝑡𝑖𝑟𝑒;
# deschide fişier cu opţiune de scriere # deschide fişier în citire
# actualizează fişier # citeşte fişier
# închide fişier # închide fişier
𝑀𝐶𝐹. 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝑆𝑐𝑟𝑖𝑒𝑟𝑒; 𝑀𝐶𝐹. 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝐶𝑖𝑡𝑖𝑟𝑒;
-------------- --------------
coend.

6
Monitor 𝑀𝐶𝐹;
int 𝑓;
condition 𝐴1 , 𝐴2 ;
procedure 𝑎𝑐𝑐𝑒𝑠𝑆𝑐𝑟𝑖𝑒𝑟𝑒(); procedure 𝑎𝑐𝑐𝑒𝑠𝐶𝑖𝑡𝑖𝑟𝑒();
begin begin
while (𝑞𝑢𝑒𝑢𝑒(𝐴2 )) 𝑤𝑎𝑖𝑡(𝐴1 ); while (𝑞𝑢𝑒𝑢𝑒(𝐴2 )) 𝑤𝑎𝑖𝑡(𝐴1 );
while (𝑓 ! = 0) 𝑤𝑎𝑖𝑡(𝐴2 ); while (𝑓 == −1) 𝑤𝑎𝑖𝑡(𝐴2 );
𝑓 = −1; 𝑓 + +;
𝑛𝑜𝑡𝑖𝑓𝑦(𝐴1 ); 𝑛𝑜𝑡𝑖𝑓𝑦(𝐴1 );
end end

procedure 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝑆𝑐𝑟𝑖𝑒𝑟𝑒(); procedure 𝑠𝑓𝑎𝑟𝑠𝑖𝑡𝐶𝑖𝑡𝑖𝑟𝑒();


begin begin
𝑓 = 0; 𝑓 − −;
𝑛𝑜𝑡𝑖𝑓𝑦(𝐴2 ); if (! 𝑓) 𝑛𝑜𝑡𝑖𝑓𝑦(𝐴2 );
end end
begin % iniţializarea variabilelor partajate
𝑓 = 0;
end. // Monitor 𝑀𝐶𝐹

Concluzii cu privire la monitoare


Mecanismul de sincronizare între procese bazat pe monitoare a fost conceput în spiritul
programării orientate pe obiecte. Astfel, în aceeaşi structură au fost reunite atât variabilele
partajate cât şi operaţiile de lucru cu acestea, operaţii reunite în cadrul unor funcţii/
proceduri/metode. Programele au devenit astfel mai clare şi mai uşor de verificat întrucât
tot ce ţine de comunicarea şi sincronizarea între procesele paralele au fost reunite într-un
singur loc. În ceea ce priveşte eficienţa sincronizării proceselor, trebuie reţinut faptul că
sincronizarea pe condiţie se face prin aşteptare pasivă.
Cu toate acestea, mecanismul de sincronizare între procese bazat pe monitoare prezintă
şi unele neajunsuri. Sincronizarea pe condiţie se face prin operaţii primitive gestionate în
mod explicit de către programator. În fapt, operaţiile 𝑤𝑎𝑖𝑡 şi 𝑠𝑖𝑔𝑛𝑎𝑙/𝑛𝑜𝑡𝑖𝑓𝑦 sunt operaţii
primitive de nivel scăzut, similare primitivelor 𝑃 şi 𝑉 folosite în lucrul cu semafoare. Prin
urmare, folosirea acestor operaţii implică multă atenţie din partea programatorilor. De
exemplu, omiterea dintr-o eroare de programare a unei operaţii 𝑠𝑖𝑔𝑛𝑎𝑙/𝑛𝑜𝑡𝑖𝑓𝑦 poate lăsa
resurse şi procese blocate pe timp nelimitat.
În multe situaţii monitorul se dovedeşte o structură mai rigidă, ce afectează gradul de
paralelism în derularea proceselor. De exemplu, la problema producători-consumatori,
soluţia îmbunătăţită care să permită ca o operaţie de depunere şi una de extragere să se
desfăşoare în paralel nu este posibilă în cadrul mecanismului bazat pe 𝑚𝑜𝑛𝑖𝑡𝑜𝑎𝑟𝑒.

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