Date post: | 28-Nov-2015 |
Category: |
Documents |
Upload: | mihaela-oleinicov |
View: | 26 times |
Download: | 4 times |
1
1. NOŢIUNI DE BAZĂ ŞI CLASIFICĂRI 2
2. Noţiuni şi termeni din domeniul resurselor tehnice 2
3. Noţiuni şi termeni din domeniul sistemelor de operare 2
4. Tipuri de sisteme de operare, obiective şi funcţii 3
5. Exemple de sisteme de operare 3
6. Cazul calculatoarelor personale 3
7. Comanda unor procese industrial 4
8. Sisteme tranzacţionale 4
9. Sisteme în timp partajat 4
10. SISTEMUL DE OPERARE ŞI PROCESELE 5
11. MAŞINĂ IERARHICĂ ŞI MAŞINĂ EXTINSĂ 5
12. ALTE PUNCTE DE VEDERE ASUPRA SISTEMELOR DE OPERARE 5
13. Abordare funcţională 6
14. Abordare din punctul de vedere al interfeţei cu utilizatorul 6
15. EVOLUŢIA SISTEMELOR DE OPERARE 6
16. De la "poartă deschisă " la tratarea pe loturi 6
17. Multiprogramarea şi partajarea timpului 7
18. Organizarea intrărilor - ieşirilor în memorii tampon 7
19. Multiprogramarea 8
20. Sisteme cu timp partajat 8
21. Windows, Unix şi alte sisteme 8
22. SО UNIX şi standardele sistemelor deschise 9
23. OSF-1 şi alte variante UNIX 9
24. Standarde UNIX 9
25. Sisteme de operare cu micronucleu 10
2
1.NOŢIUNI DE BAZĂ ŞI CLASIFICĂRI
Sistem de operare- destinaţia este administrarea (gestiunea, controlul) resurselor tehnice
principale şi asigurarea unei interfeţe comode (plăcute, prieteneşti) între utilizator şi
calculator.(Sistem de operare înţelegem modulele program ale unui sistem de calcul, care
administrează resursele tehnice (procesoare,memoria operativă şi secundară, dispozitive de
intrare/ieşire, fişiere)).Functii SO:utilizarea resurselor hardware în scopuri speciale poate fi
necesar să se creeze un sistem de operare propriu sau să se introducă modificări în sistemul
existent;de alegerea corectă a sistemului de operare şi a versiunii concrete poate depinde
viabilitatea şi eficacitatea sistemului de calcul;este ideal ca utilizatorul să interacţioneze cu
sistemul de operare cunoscând toate subtilităţile ultimului, deoarece sistemul de operare este
un intermediar între calculator şi utilizator;
2.Noţiuni şi termeni din domeniul resurselor tehnice.
Un calculator constă dintr-un ansamblu de componente funcţionale fizice şi logice, care
cooperează pentru a satisface cerinţele utilizatorilor privind introducerea, stocarea,
prelucrarea, transmisia şi căutarea informaţiilor. Suportul fizic (resurse tehnice, hardware)
constituie nivelul inferior al sistemului de calcul construit pe baza unor componente
electronice, magnetice, optice, mecanice etc. Funcţii esenţiale ale calculatorului: iniţializarea
(bootup), introducerea datelor, procesarea datelor, stocarea datelor şi extragerea
rezultatelor. Prin structura unui calculator vom înţelege componentele (dispozitivele) care
formează calculatorul şi legăturile dintre ele. Componentele principale sunt: procesorul,
memoria, unităţile de stocare pe termen lung, dispozitivele de intrare-ieşire (tastatura,
display-ul, mouse-ul etc.). Componentele principale se conectează la placa de bază direct sau
prin conectoare special.interactionind si cu alte elemente.Mai mentionam notiuni ca
:,magistrala interne de date, magistrala externe de date, memorie, ceas electronic .
3.Noţiuni şi termeni din domeniul sistemelor de operare
Un sistem de operare este un ansamblu de programe de control şi de serviciu care
ghidează un calculator în executarea sarcinilor sale şi asistă programele de aplicaţie şi
utilizatorul prin intermediul anumitor funcţiuni. Natura funcţiilor şi modul în care acestea
sunt realizate determină atributele care caracterizează un sistem de operare: timpul de
răspuns, simultaneitatea utilizării, eficienţa, partajarea şi protecţia, generalitatea,
flexibilitatea, extensibilitatea, fiabilitatea şi disponibilitatea, transparenţa şi vizibilitatea.
Timpul de răspuns exprimă durata intervalului delimitat de lansarea unei cereri de serviciu
şi achitarea acesteia de către sistemSimultaneitatea utilizării măsoară gradul în care un
sistem poate să execute în acelaşi timp mai multe lucrări.Eficienţa măsoară proprietatea unui
sistem de a folosi în mod optim resursele de care dispune.Partajarea şi protecţia
caracterizează nivelul la care utilizatorii au posibilitatea să utilizeze în comun informaţia
prezentă în sistem şi nivelul la care pot să comunice între ei, în deplină siguranţă
Generalitatea, flexibilitatea, extensibilitatea măsoară gradul în care un sistem poate fi
3
folositor şi adaptabil unui context specific Resursele program reprezintă seturi de programe
şi date utilizate pentru soluţionarea anumitor probleme. Multiprogramarea este un termen
utilizat în cazul unui sistem în care pot exista simultan câteva procese în stare de execuţie.
Resursele hardware de protecţie sunt utilizate cel mai des pentru controlul accesării
memoriei. Resursele hardware de întrerupere permit sistemului de operare să coordoneze
operaţiile simultane
4.Tipuri de sisteme de operare, obiective şi funcţii
Pot fi evidenţiate sisteme de operare :secvenţiale(execută la un moment dat un singur
program, care trebuie terminat înainte de a lua un alt program în consideraţie),cu
multiprogramare(acceptă la un moment dat mai multe programe în memoria centrală,
acestea aflându-se în diverse stadii de execuţie.)cu prelucrare multiplă(dispune de mai
multe procesoare, care pot să execute simultan unul sau mai multe programe),în timp real,
etc. Obiective-maximizarea eficienţei sistemului de calcul şi a satisfacţiei utilizatorilor,
cererea de minimizare a posibilităţii de apariţie a unor erori , de maximizare a transparenţei
sistemului de operare, garantarea securităţii datelor, optimizarea controlului comunicaţiilor ,
efortului concepţie-realizare a sistemului. Un sistem de operare are urm functii:să păstreze
informaţia despre starea fiecărei resurse să ia decizia cărui proces să i se aloce resursa, în ce
cantitate şi când să aloce resursa şi la momentul respectiv să o retragă.
5.Exemple de sisteme de operare
Sistemele de operare pot fi utilizate la calculatoarele personale,comanda unor procese
industriale,sisteme tranzacţionale(care include volume de date importante),sisteme în timp
partajat.
6.Cazul calculatoarelor personale
Configuraţia cea mai simplă a unui calculator personal (PC) include o unitate centrală, o
memorie principală, un display, o tastatură şi un mouse. Sistemul de operare va acorda
servicii prin intermediul unui limbaj special, numit limbaj de comandă.Exemplu de
secvenţe tipice de activităţi în cazul unui PC:elaborarea unui program;introducerea
programului cu ajutorul tastaturii şi a unui editor de texte;executarea programului
introducându-se datele necesare de la tastatură şi extrăgând rezultatele la display sau
imprimantă;modificarea programului, dacă rezultatele nu sunt satisfăcătoare şi repetarea
execuţiei;perfectarea versiunii finale a programului, inclusiv documentarea la necesitate a
acestuia;exploatarea unui program;cererea de executare a unui program deja existent. Într-un
atare sistem funcţia partajare a resurselor am considerat-o lipsă, or PC-ul este folosit de un
singur utilizator care are controlul total asupra acestuia. Funcţiile principale vizibile ale
sistemului de operare constau în administrarea fişierelor, realizarea operaţiilor de
intrare/ieşire şi interpretarea comenzilor provenite de la interfaţa utilizator-sistem de
operare.Pentru acest tip de sisteme cele mai importante caracteristici
sunt:fiabilitatea;eficacitatea;simplitatea utilizării;facilitatea extensibilităţii prin adăugarea
unor utilite noi sau adaptarea la periferice noi.
7.Comanda unor procese industriale
4
Ex:Fie la o uzină chimică sunt utilizate doua produse iniţiale A şi B pentru sinteza
produsului C .Procesul de producere este comandat de un calculator care îndeplineşte
următoarele funcţii:Reglare,Înregistrare. Securitate. Acest mod de funcţionare introduce
unele restricţii.măsurările -făcute periodic; fie T valoarea intervalului de timp dintre două
măsurări consecutive (perioada de eşantionare), iar t - timpul total de prelucrare a datelor de
către calculator .Sistemul va funcţiona doar în cazul respectării relaţiei de restricţionare t
T.Securitatea sistemului are prioritate maximăFuncţiile principale ale sistemului de operare
sunt:acţionarea organelor externe;evidenţa timpului real ;reacţia la evenimentele exterioare
(oprire de urgenţă);gestiunea informaţiilor (păstrarea şi întreţinerea fişierului jurnalului de
bord).În cazul acestor sisteme caracteristica principală este fiabilitatea, or rezultatele unei
funcţionări neadecvate pot fi catastrofale. Sistemul trebuie să garanteze un serviciu minim în
cazul unor căderi în pană a dispozitivelor tehnice, unor evenimente accidentale sau erori
umane.
8.Sisteme tranzacţionale
Caracteristicile principale ale sistemelor cu tranzacţii sau tranzacţionale sunt
următoarele:sistemul gestionează un set de informaţii sau baze de date, care pot atinge
volume importante;asupra acestor informaţii pot fi executate un anumit număr de operaţii
predefinite, sau tranzacţii, adesea interactive;sistemul este dotat cu un mare număr de puncte
de acces şi un mare număr de tranzacţii se pot derula simultan.Ca exemplu pot fi menţionate
sistemele de rezervare a biletelor de tren sau avion, de gestionare a conturilor
bancare,Restricţiile sunt în primul rând legate de integritatea şi coerenţa internă a
informaţiilor, care formează bazele de date. Calităţile obligatorii ale unui sistem tranzacţional
sunt disponibilitatea şi fiabilitatea; pentru unele sisteme poate fi importantă şi toleranţa la
defecţiuni. O caracteristică importantă ale sistemelor tranzacţionale este multitudinea
activităţilor paralele, iar în multe cazuri şi repartizarea geografică a componentelor.
9.Sisteme în timp partajat
Destinaţia principală a unor astfel de sisteme este furnizarea serviciilor necesare unei
mulţimi de utilizatori, fiecare dintre ei beneficiind:de servicii echivalente serviciilor unui
calculator individual;de servicii legate de existenţa unei comunităţi de utilizatori: partajarea
informaţiilor, comunicaţii între utilizatori.Problemele care apar datorită conceptului de
partajare a timpului sunt o combinaţie a problemelor existente în cazul unui calculator
individual cu cele din sistemele tranzacţionale şi pot fi clasificate după cum
urmează:definirea maşinii virtuale oferite fiecărui utilizator;partajarea şi alocarea resurselor
fizice comune: procesoare, memorii, organe de comunicaţie;gestionarea informaţiilor
partajate şi a comunicaţiilor.Caracteristicile obligatorii unui atare sistem combină în egală
măsură calităţile unui sistem de operare al unui calculator individual şi al unui sistem
tranzacţional: disponibilitatea, fiabilitatea, securitatea, exploatarea optimă a caracteristicilor
resurselor fizice, calitatea interfeţei şi serviciilor utilizatorului, facilitatea adaptării şi
extensibilităţii.
5
10.SISTEMUL DE OPERARE ŞI PROCESELE
Proces-o suită temporală de execuţii de instrucţiuni, fiind o entitate de bază în
descrierea sau analiza funcţionării unui sistem. Evoluţia în timp a unui proces presupune un
consum de resurse, dictat de natura şi complexitatea instrucţiunilor de executat. Orice
utilizare a unei resurse este asociată, la un moment dat, unui proces şi procesul respectiv îşi
asumă răspunderea utilizării acestei resurse. Ciclul de viaţă a unui proces poate fi reprezentat
printr-un set de stări ale procesului şi trecerea de la o stare la alta. Vom evidenţia trei stări
elementare ale unui proces: proces ales (sau exe) – procesului i s-a alocat un procesor, este
în curs de execuţie, proces blocat – procesul aşteaptă să se producă un anumit eveniment, a
cărui apariţie este indispensabilă, proces eligibil – procesul are la dispoziţie toate resursele
necesare lipsă fiind doar procesorul, Sistemul de operare este acea componentă, care va ghida
procesul prin toate aceste stări. pentru modelarea procesului real au fost adăugate trei stări
suplimentare: prezentare –utilizatorul prezintă sistemului sarcina, sistemul trebuie să
reacţioneze la cererea utilizatorului, păstrare –sarcina este reprezentată în formă internă, dar
resursele nu sunt încă alocate,terminare – calculele corespunzătoare procesului au luat
sfârşit, toate resursele alocate procesului pot fi eliberate şi întoarse istemului
11.MAŞINĂ IERARHICĂ ŞI MAŞINĂ EXTINSĂ
Setul de instrucţiuni realizat hardware împreună cu instrucţiunile suplimentare ale
sistemului de operare formează sistemul de comenzi al maşinii extinse.O masina extinsa e
formata din citeva procese,masina goala si sistemul de operare.Notiunuea de masine extinsa
în cazul sistemelor de operare, poate fi utilizat în două nivele, astfel conduce la noţiunea de
maşină ierarhică. Primul nivel - funcţiile cheie, utilizate de majoritatea modulelor de
sistem, pot fi realizate în cadrul unei maşini extinse interne şi Nivelul doi - unele module
pot fi executate în cadrul unei maşini extinse externe. Modulele sistemului, plasate în cadrul
maşinii extinse, spre deosebire de modulele care aparţin straturilor proceselor, formează
nucleul sistemului de operare
12.ALTE PUNCTE DE VEDERE ASUPRA SISTEMELOR DE OPERARE:
Abordare din punctul de vedere al interfeţei cu utilizatorul,Abordare funcţională:
13.Abordare funcţională:
Destinaţia principală a unui sistem de operare pentru categoria de utilizatori obişnuiti
la care noţiuni cum ar fi administrarea memoriei cu paginaţie sau driverele dispozitivelor nu
semnifică prea multe,este punerea la dispoziţie a unui set de programe care ar ajuta în
6
formularea şi rezolvarea problemelor concrete. Abordarea sistemelor de operare din acest
punct de vedere (abordare funcţională) poate conduce la confundarea lor cu unele programe,
utile şi foarte importante (translatoare, biblioteci, medii integrate, etc.). Pentru a evita
posibilitatea apariţiei unei astfel de probleme aceste programe, de obicei, nu sunt
considerate componente ale sistemului de operare.
14.Abordare din punctul de vedere al interfeţei cu utilizatorul
Interfaţa sistemului de operare cu utilizatorul prezintă un interes aparte. Progresul în
acest domeniu este spectaculos, dacă vom lua în consideraţie că în primele sisteme
utilizatorul era obligat să indice în mod explicit şi manual fiecare pas cu ajutorul Job
Control Language Microprocesoarele şi memoriile anilor ’70 au pus problema lansării pe
piaţă a calculatoarelor personale (PC) cu toate consecinţele respective. Una din consecinţe
este şi interfaţa utilizator-calculator, sistemul de operare devenind până la urmă responsabil
de aceasta. Interfaţa grafica a utilizatorului (Graphical User Interface - GUI) a apărut mai
întâi ca un complement al sistemului de operare (pentru MS DOS - Windows 1, Windows 2
sau chiar Windows 3, de exemplu), pentru ca mai apoi să fie integrată în cadrul sistemului .
15.EVOLUŢIA SISTEMELOR DE OPERARE
O analiză cronologică a dezvoltării sistemelor de operare este greu de realizat,
deoarece multe din principiile foarte importante au fost realizate pentru prima dată cu mult
înainte de a deveni acceptate. Primele sisteme erau caracterizate prin prelucrarea
secvenţială a taskurilor. Timpul de execuţie a programelor era relativ mare, instrumentele
de depanare – primitive, fiecare programator îşi încărca în mod individual programul
(pachetul de cartele perforate), apăsa butoane, controla conţinutul locaţiunilor de memorie,
etc. (1950 – 1956).Primele încercări de prelucrare pe loturi (1956 – 1959).Odată cu
creşterea complexităţii calculatoarelor, îndeosebi în ceea ce consta administrarea
dispozitivelor periferice, au fost propuse sisteme supervizoare (1959 – 1963). care se aflau
în memoria calculatorului în mod constant şi acordau utilizatorilor servicii în gestiunea
operaţiilor de intrare/ieşire Au urmat apoi sistemele cu multiprogramare, menite la început
să rezolve problema concordării vitezei de calcul a unităţii centrale şi a perifericelor. După
1965 au apărut primele sisteme cu partajare a timpului Memoria virtuală şi maşinile
virtuale sunt nişte principii care nici până astăzi nu au fost exploatate până la capăt.
Progresele ultimilor ani în domeniul resurselor tehnice au permis implementarea acestor
principii nu numai în cadrul sistemelor de calcul mari, ci şi pentru calculatoarele personale.
Specificaţiile sistemelor de operare au fost în mare măsură standardizate, diversitatea SO
devine tot mai mică, mulţi specialişti exprimându-şi îngrijorarea de o posibilă monopolizare
a domeniului în viitorul apropiat.
16.De la "poartă deschisă " la tratarea pe loturi
Primele calculatoare nu dispuneau de sisteme de operare. Fiecărui utilizator i se
rezerva pentru un timp determinat calculatorul cu toate resursele acestuia. Interacţiunea era
7
directă, programul şi datele fiind introduse în mod manual sub formă de zerouri şi unităţi.
Utilitele care au apărut aveau destinaţia de a asista elaborarea programelor (asambloare,
compilatoare, etc.) sau de a facilitata operaţiile de intrare-ieşire.Acest mod de exploatare,
numit "poartă deschisă" ,era de o eficacitate minimă, dispozitive foarte costisitoare fiind
utilizate ineficient. Din această cauză la sfârşitul anilor '50 au apărut primele "monitoare de
înlănţuire" - programe care permiteau executarea secvenţială a unui set de lucrări, pregătite
anticipat, trecerea de la o lucrare la alta fiind automatizată.Funcţia principală a unui atare
sistem era gestiunea resurselor: memoria, procesorul, intrarea-ieşirea. dând posibilitatea
sporirii la maximum a randamentului calculatorului principal.Deşi utilizarea monitoarelor
de înlănţuire a ameliorat notabil randamentul utilizării procesorului, acest randament
rămânea foarte scăzut din cauza că procesorul nu era eliberat în timpul operaţiilor de
intrare-ieşire. O soluţionare ar fi constat în utilizarea a două calculatoare - unul (principal)
pentru executarea programelor şi altul (auxiliar) pentru operaţiile de intrare-ieşire. O
planificare adecvată a executării lucrărilor permitea utilizarea celor două calculatoare în
paralel, dând posibilitatea sporirii la maximum a randamentului calculatorului principal.
17.Multiprogramarea şi partajarea timpului
Utilizarea principiului multiprogramării sau partajarea memoriei între mai mulţi
utilizatori a permis o utilizare şi mai bună a procesorului central. Exploatarea unui
calculator conform principiului timpului partajat oferă utilizatorilor posibilităţi analogice
unui calculator individual, permiţând beneficiul unor servicii comune la un preţ redus.
18.Organizarea intrărilor - ieşirilor în memorii tampon
Un canal este un procesor specializat în executarea autonomă a operaţiilor de intrare-
ieşire, paralel cu procesul de prelucrare a informaţiilor. Viteza de lucru a organelor
periferice este relativ mică din cauza unor dispozitive mecanice care intră în componenţa
acestora. Pentru excluderea influenţei perifericelor asupra vitezei de lucru a sistemului de
calcul s-a propus să se păstreze în memorie în anumite zone tampon datele de intrare (care
vor fi utilizate la necesitate) şi rezultatele (care vor fi imprimate în mod autonom) mai
multor lucrări. Schema intrari/iesiri in memoria tampon
Pentru a exclude utilizarea ineficientă a memoriei operative prin formarea zonelor-
tampon, acestea erau organizate în memoria secundară de capacitate înaltă, transferurile
între aceste două nivele ale memorie fiind de asemenea comandate de un canal.Deşi
utilizarea memoriilor tampon prezintă o serie de avantaje în vederea sporirii randamentului
dispozitivelor calculatorului, totuşi două momente negative pot fi menţionate:atunci când
lucrarea în curs de execuţie are nevoie de nişte date unitatea centrală rămâne inactivă pe
toată perioada citirii acestora;o lucrare de scurtă durată, sosită în timpul execuţiei unei
lucrări "lungi", trebuie să aştepte terminarea acesteia din urmă.
Intrăr
Lucrări
la Debit Debit
Debit Rezulta
te la
Prelucrarea Ieşire Fig.1.12. Buferizarea intrărilor-
8
19.Multiprogramarea
Multiprogramarea implica prezenţa simultană în memoria operativă a mai multor
programe sau părţi de programe.
Schema de functionare-multiprogramare:
Avantajele şi restricţiilemultiprogramării :un sistem cu multiprogramare este mai
complicat pentru că el trebuie să asigure partajarea memoriei şi protecţia reciprocă a
programelor;multiprogramarea necesită dispozitive speciale pentru reactivarea programelor
şi protecţia memoriei;un sistem cu multiprogramare asigură o utilizare mai uniformă a
diferitor resurse: unitatea centrală, memoria, organele de intrare-ieşire;multiprogramarea
permite reducerea timpului de răspuns în cazul lucrărilor de durată mică într-un sistem cu
prelucrare secvenţială.
20.Sisteme cu timp partajat
Un sistem de operare cu partajarea timpului trebuie să garanteze fiecărui utilizator un
timp acceptabil de răspuns. Acest rezultat este obţinut prin alocarea succesivă a
procesorului pentru tranşe de timp foarte mici (cuante) programelor utilizatorilor.
Activitatea unui utilizator conţine două componente: timpul de reflecţie (gândire), în care
utilizatorul elaborează, propune subiecte de lucru, introducând în calculator informaţii şi
timpul de aşteptare, când aşteaptă executarea de către sistem a serviciului cerut.
Dezvoltarea sistemelor de operare cu partajarea timpului a pus în evidenţă importanţa
interacţiunii om-calculator.
21.Windows, Unix şi alte sisteme
Paralel cu evoluţia tehnică şi funcţională a sistemelor de operare a avut loc şi o
importantă evoluţie conceptuală, care a permis o mai bună înţelegere a funcţionării
sistemelor de operare şi a condus la elaborarea unor metode proprii de concepere.Debutul
unei cercetări ştiinţifice a sistemelor de operare poate fi considerat anul 1964, care a
succedat o etapă importantă de dezvoltare tehnică: primele sisteme cu partajare a timpului
(Thor, CTSS), anunţarea seriei IBM 360 şi introducerea canalelor de intrare-ieşire, prima
memorie paginată (Atlas), etc.În perioada 1965-1968 au fost elaborate noţiunile necesare
conştientizării gestionării activităţilor fizice sau conceptuale paralele: proces secvenţial,
formularea şi soluţionarea unor probleme de excludere mutuală, sincronizarea şi inventarea
semaforului.Sunt propuse primele metode de specificare şi control al validităţii
sincronizărilor.In 1962 apare prima memorie paginată.În 1965 este fundamentată noţiunea
de segmentare.În 1966 este propus un model de arhitectură pentru calculatoare cu partajare
a timpului.Problemele partajării şi protecţiei informaţiei, alocării resurselor conduc la
noţiunea de memorie virtuală, care permite izolarea mecanismelor de gestionare a
ansamblului “memorie principală - memorie secundară”, lăsând utilizatorilor simpli
impresia unui spaţiu de adresare uniform (contiguu). Au fost introduse noţiunile de
modularitate şi structurare ierarhică, obiect, etc.Astăzi sistemele de operare în sensul
tradiţional de concepere sunt obiectul unor elaborări industriale, decât de cercetare.Aceasta
este datorat atât achiziţionării unei rezerve extraordinare de metode şi algoritmi, cât şi
9
standardizării stricte a funcţiilor şi interfeţelor sistemelor de operare.(Windows,Unix sunt
SO care au evoluat cu timpul)
22.SО UNIX şi standardele sistemelor deschise
Sistemul de operare UNIX, primul sistem mobil care asigură un mediu fiabil de
dezvoltare şi utilizare a softului de aplicaţie, este fundamentul practic de elaborare a
sistemelor fizico-logice deschise. Implementarea largă a sistemului de operare UNIX a
permis trecerea de la declararea sistemelor deschise la dezvoltarea practică a acestui
concept.Pot fi evidenţiate câteva versiuni ale SO UNIX, care diferă atât prin realizare, cât şi
prin interfeţe şi semantic. Sistemul de operare UNIX, primul sistem mobil care asigură un
mediu fiabil de dezvoltare şi utilizare a softului de aplicaţie, este fundamentul practic de
elaborare a sistemelor fizico-logice deschise. Implementarea largă a sistemului de operare
UNIX a permis trecerea de la declararea sistemelor deschise la dezvoltarea practică a
acestui concept. Modulele sursă ale SO UNIX au fost scrise de către colaboratorii
companiei AT&T care mai tirziu a creat compania USL (UNIX System Laboratories), care
avea în şarjă exclusivă dezvoltarea şi susţinerea modulelor sursă ale SO UNIX.Versiunile
UNIX sunt: UNIX System V 4.0, UnixWare 2.0 bazată pe System V 4.2,versiunea SVR
4.2,s.a. Pe parcursul a mai multor ani sistemul de operare de bază al companiei Sun a fost
UNIX BSD,care a introdus o serie de modificari si extensii in versiunea UNIX System V
4.0.
23.OSF-1 şi alte variante UNIX
Open Software Foundation (OSF) a fost prima companie comercială, care a încercat
elaborarea SO UNIX în baza micronucleului Mach. A fost creat sistemul de operare OSF-1,
care nu era în sens de licenţiere „curat”, deoarece folosea o parte a modulelor iniţiale din
SVR 4.0.Variantele SO UNIX, propuse de Universitatea din California, sunt o alternativă
reală pentru UNIX AT&T. Realizarea originală a SO UNIX pentru platformele Intel,
LINUX tot este o varianta UNIX.-un sistem de operare foarte popular în mediul studenţesc,
care are şi una din cele mai populare teleconferinţe în Internet. Odată cu ieşirea SO UNIX
pe piaţă şi creşterea substanţială nu numai a numărului de utilizatori, ci şi a numărului de
specialişti din toate colţurile lumii, care propuneau modificări şi chiar variante proprii, a
apărut necesitatea elaborării unor standarde, care ar conduce la sisteme compatibile.
Activitatea de standardizare a început cu mai mult de 10 ani în urmă,a obtinut rezultate, dar
inca este puţin probabil să se ajungă la finiş într-un viitor apropiat.
24.Standarde UNIX
Unul dintre primele standarde de-facto a fost cel publicat de USL pentru versiunea SO
UNIX System V Release 4 - System V Interface Definition (SVID). Majoritatea variantelor
comerciale respectau standardul SVID,care nu era un standart official. Cel mai popular
standard, adoptat de ISO definea cerinţele minime pentru componentele unui sistem de
operare.Pentru lumea UNIX este foarte important şi standardul limbajului de programare C,
10
adoptat mai întâi de ANSI şi apoi de ISO. În acest standard sunt specificate, în afara
limbajului C, bibliotecile necesare într-o realizare standard. Deoarece chiar de la apariţie
limbajul C şi sistemele de programare respective erau strâns legate de UNIX, componentele
bibliotecilor standard corespundeau exact mediului standard al SO UNIX.Mai menţionăm
standardul de-facto SPARC Complience Definition, propus de organizaţia SPARC
International, propunerea organizaţiei 88/Open pentru procesoarele RISC Motorola,
standardul sistemului de ferestre, susţinut de X Consorţium (Institutul de Tehnologie din
Massachussets) şi OSF/Motif, elaborat de Open Software Foundation
25.Sisteme de operare cu micronucleu
Micronucleul este partea minimă principală a unui sistem de operare, folosită pentru
asigurarea modularităţii şi transportabilităţii. Noţiunea de micronucleu a fost introdusă de
compania Next prin sistemul de operare cu micronucleul Mach.Nucleul acestui sistem de
operare, de dimensiuni mici, în jurul căruia se situau subsistemele executate în regim user,
trebuia să asigure o flexibilitate şi modularitate foarte înaltăutilizarea micronucleului Mach
a permis introducerea administrării mesajelor şi a unei serii de funcţii de serviciu orientate
pe obiecte, în baza cărora a fost creată o interfaţă grafică elegantă a utilizatorului cu
mijloace simple de configurare, administrare şi dezvoltare programUrmătorul SO cu
micronucleu a fost MS Windows NT, în care momentul principal declarat era, în afara
modularităţii, transportabilitatea.La tehnologia „micronucleară” au aderat si alte companii
renumite.
11
26.MODUL SECVENŢIAL DE EXECUŢIE A UNUI PROGRAM 12
27.Noţiuni fundamentale 12
28.Starea şi contextul procesorului 13
29.ÎNTRERUPERI, DEVIERI, APELAREA SUPERVIZORULUI 13
30.Activităţi asincrone 14
31.Mecanisme de comutare a contextului 14
32.Întreruperi 15
33.Devieri şi apelarea supervizorului 17
34.Exemple de sisteme de întreruperi 18
35.IMPLEMENTAREA MECANISMELOR DE COMUTARE A CONTEXTULUI 18
36.Utilizarea devierilor şi apelării supervizorului 19
37.Exemple de utilizare a întreruperilor 22
38.PROGRAMAREA OPERAŢIILOR DE INTRARE-IEŞIRE 26
39.Organizarea generală 26
40.Metode de comandă a perifericelor 29
41.Intrări-ieşiri buferizate în memorie 32
42.Încărcarea initial 40
43.Gestionarea activităţilor paralele. Exemple introductive 41
44.Administrarea tamponată a intrărilor-ieşirelor 41
45.Comanda unui proces industrial 43
46.Noţiune de proces secvenţial 44
47.Proces unic. Context 45
48.Relaţii între procese 46
49.Mulţimi de procese. Paralelism 46
50.Concurenţa proceselor. Resurse virtuale 48
12
26. MODUL SECVENŢIAL DE EXECUŢIE A UNUI PROGRAM
Nucleul unui calculator este format dintr-o memorie adresabilă, în care sunt păstrate
instrucţiunile şi datele programului, şi procesorul, care interpretează instrucţiunile. Instrucţiunile
şi datele se află în segmente distincte, prin segment înţelegând o mulţime de informaţii,
desemnate şi manipulate ca un tot întreg, care ocupă în memorie o suită contiguă de
amplasamente. Presupune că segmentele care conţin programul nu pot fi modificate în timpul
execuţiei acestuia.
Execuţia instrucţiunilor, care formează un program secvenţial, conduce la evoluţia stării
calculatorului. Evoluţia stării calculatorului poartă un caracter discret, starea este observabilă
doar în momente de timp numite puncte de observare, care corespund, de obicei, începutului şi
sfârşitului unei instrucţiuni. Unele instrucţiuni mai complexe pot conţine puncte observabile
intermediare.
27. Noţiuni fundamentale
Vom descrie un mecanism general pentru execuţia programelor secvenţiale, formate dintr-o
suită de activităţi, rezultate din execuţia unei proceduri sau corutine. Acest mecanism realizează
funcţiile următoare:
Salvarea şi restabilirea contextului la apelare şi retur,
Transmiterea parametrilor între procedurile apelantă şi apelată,
Administrarea unei zone de lucru proprii fiecărei proceduri, cu
permisiunea apelurilor recursive.
Exemplul 2.1. O procedură p (apelantă) provoacă execuţia unei proceduri q
(apelate) cu ajutorul unei secvenţe de apel care conţine următoarele etape:
Pregătirea parametrilor, transmişi de către procedura p procedurii q,
Salvarea parţială a contextului lui p, necesar la retur,
Înlocuirea contextului procedurii p prin contextul lui q.
La revenire din procedura q avem o schemă practic simetrică, doar contextul lui q fiind
pierdut:
Pregătirea rezultatelor, transmise de către procedura q procedurii p,
Restabilirea contextului procedurii p, salvat înainte de apel.
Exemplul 2.2. În cazul funcţionării în corutine (proceduri simetrice, recursie
mutuală – două proceduri se pot apela reciproc), procedurile apelantă şi apelată joacă
un rol simetric: secvenţa de retur este identică cu cea de apel. Activitatea care rezultă
din apelul unei proceduri p ia în calitate de context iniţial contextul salvat la ultimul
apel executat de p. Primul apel al unei proceduri trebuie să specifice valoarea iniţială
a contextului său.
Secvenţa de schimbare a contextului (reluarea) conţine următoarele etape (p este corutina
părăsită, q este cea reluată):
13
Pregătirea parametrilor, transmişi de către procedura p procedurii q,
Salvarea parţială a contextului lui p, care trebuie să fie regăsit la
reluare,
Restabilirea contextului salvat la ultimul abandon al lui q sau formarea
contextului iniţial în cazul primului apel.
28. Starea şi contextul procesorului
Starea procesorului este determinată de conţinutul registrelor acestuia. Registrele pot fi:
adresabile, numite registre generale, manipulate de programe,
registre speciale, de obicei grupate sub forma unor informaţii sintetice,
numite cuvânt de stare program sau cuvânt de stare a procesorului (în engleză,
program status word, PSW).
Cuvântul de stare a procesorului conţine informaţii, care pot fi clasificate astfel:
1) Informaţii referitoare la starea procesorului:
(a) Starea de execuţie. Procesorul se poate afla în starea activ în care
îndeplineşte instrucţii, sau în starea de aşteptare este în mod obligator rezultatul
unei întreruperi.
(b) Modul de funcţionare. Din considerente de protecţie este util să se
permită doar programelor sistemului de operare executarea unor instrucţiuni
anumite (speciale), programele utilizatorilor neavând acces la aceste instrucţiuni.
Astfel instrucţiunile rezervate modului supervizor pot fi numite privilegiate, aici
pot fi găsite instrucţiunile de intrare-ieşire şi cele legate de întreruperi şi protecţie.
(c) Masca întreruperilor.
2) Informaţii referitoare la contextul accesibil al memoriei şi drepturile de acces
asociate: tabele de segmente, indicatori de protecţie a memoriei, etc.
29. ÎNTRERUPERI, DEVIERI, APELAREA SUPERVIZORULUI
O întrerupere este comutarea contextului procesorului declanşată de o cauză externă
derulării instrucţiunii curente. Fizic, întreruperea înseamnă trimiterea unui semnal procesorului,
acest semnal provocând schimbarea stării unuia dintre indicatorii, consultaţi în cursul executării
fiecărei instrucţiuni. O întrerupere permite să cerem procesorului să suspende executarea
programului curent, din primul punct întreruptibil, şi să treacă la execuţia unui program
predefinit. Acesta din urmă este numit program de tratare a întreruperii.
Spre deosebire de o întrerupere, o deviere sau un apel al supervizorului sunt provocate de o
cauză legată direct de derularea instrucţiunii curente.
O deviere semnalizează o anomalie în derularea unei instrucţiuni, care prohibitează
executarea instrucţiunii. Originile pot fi diverse:
date incorecte, care conduc la imposibilitatea execuţiei corecte a instrucţiunii
(împărţirea la zero, de exemplu),
tentativa executării unei operaţii interzise de mecanismul de protecţie
(violarea protecţiei memoriei, executarea unei instrucţiuni privilegiate în modul program,
etc.),
14
instrucţiune neexecutabilă (cod neautorizat de operaţie, adresă în afara
memoriei existente, utilizarea unui dispozitiv opţional, care este lipsă în configuraţia dată,
etc.).
Un apel al supervizorului este o instrucţiune chemată să provoace o comutare a
contextului procesorului. Acest efect este analogic apelării unei proceduri, însă modificarea
contextului este mai profundă, fiindcă ea afectează întreg cuvântul de stare şi nu numai contorul
ordinal.
Destinaţia unui apel al supervizorului este de a permite apelarea unei proceduri a sistemului
de operare.
30. Activităţi asincrone
Prin asincronism înţelegem efectul care îl pot avea asupra derulării unei activităţi
anumite evenimente exterioare.
Numim protecţie reciprocă între activităţi o modificare mai profundă a contextului,
atunci când se trece de la o activitate la alta, în comparaţie cu ceea ce are loc în cazul unei
simple apelări de procedură.
Un caz tipic de asincronism este executarea intrărilor-ieşirilor simultan cu execuţia unui
program. Trebuie să fie asigurată posibilitatea informării programului despre terminarea unui
transfer de informaţii. O primă posibilitate, care nu necesită utilizarea unor dispozitive
speciale, este cea a aşteptării active, prezentată mai jos.
31. Mecanisme de comutare a contextului
Comutarea contextului unui procesor permite executarea într-o manieră indivizibilă a
următoarelor două operaţii:
trecerea cuvântului de stare într-un amplasament specificat al memoriei,
încărcarea în cuvântul de stare a conţinutului unui alt amplasament specificat
al memoriei.
Aceasta se poate întâmpla doar dacă procesorul se află într-o stare observabilă (de exemplu,
între execuţia a două instrucţiuni) sau de aşteptare. Din aceste considerente noţiunea de "punct de
întrerupere" este sinonim al noţiunii "punct observabil".
Comutarea contextului poate fi necesară din mai multe cauze distincte. Presupunem că
fiecărei cauze i-a fost asociat un număr de ordine. Pot fi întâlnite două scheme de comutare a
contextului.
1) Salvare în amplasamente fixe. Fiecărei cauze (numărul unei cauze fiind i) îi
sunt ataşate în mod constant două amplasamente de memorie adresele cărora le vom nota
prin csp_vechi[i] şi csp_nou[i] (csp semnificând cuvânt de stare program). Comutarea se
produce după cum urmează:
Mp[csp_vechi[i]]:=<cuvânt de stare program>
<cuvânt de stare program>:= Mp[csp_nou[i]]
15
În setul de instrucţiuni există o instrucţiune privilegiată schimbă_csp(adr) cu următorul
efect:
<cuvânt de stare program>:= Mp[adr].
2) Salvare într-o stivă. Aici avem acelaşi procedeu în ceea ce constă cuvântul
de stare nou. Însă cuvântul de stare vechi nu este salvat într-un amplasament fix, ci într-o
stivă specială:
ptr :=ptr+1
stiva[ptr] :=<cuvânt de stare program>
<cuvânt de stare program> := Mp[csp_nou[i]]
Instrucţiunea schimbă_csp(adr) este identică celei din 1); există însă şi o instrucţiune
restabileşte_csp, care restabileşte cuvântul de stare a procesorului folosind pentru acesta top-ul
stivei:
<cuvânt de stare program> :=stiva[ptr]
ptr :=ptr-1
Comutarea contextului, descrisă mai sus, este declanşată sub influenţa stării unor indicatori
interni pe care procesorul îi consultă la interpretarea fiecărei instrucţiuni. Conform semnificaţiei
acestor indicatori şi maniera în care ei sunt modificaţi, pot fi evidenţiate trei mecanisme de
comutare, descrise în tabelul de mai jos:
Tabelul 2.1. Mecanisme de comutare a contextului
Denumirea
mecanismului
Cauza Utilizarea
Întrerupere Exterioară
derulării instrucţiunii
curente
Reacţionare la un
eveniment asincron extern
Deviere Legată de
derularea instrucţiunii
curente
Tratarea unei erori
sau situaţii excepţionale
Apelarea
supervizorului
Comutare
explicită
Apelarea unei funcţii
a S.O.
Adesea toate aceste trei denumiri sunt înlocuite cu una singură - întrerupere.
32. Întreruperi
O întrerupere este comutarea contextului procesorului declanşată de o cauză externă
derulării instrucţiunii curente. Fizic, întreruperea înseamnă trimiterea unui semnal procesorului,
acest semnal provocând schimbarea stării unuia dintre indicatorii, consultaţi în cursul executării
fiecărei instrucţiuni. Semnalul poate proveni de la alt procesor, de la un organ de I/E, de la un
dispozitiv extern, şi în genere, de la orice proces fizic, extern procesorului întrerupt. O
întrerupere permite să cerem procesorului să suspende executarea programului curent, din primul
punct întreruptibil, şi să treacă la execuţia unui program predefinit. Acesta din urmă este numit
16
program de tratare a întreruperii (interrupt handler, eng., traitant de l'interruption, fr.).
Programul de tratare a întreruperii este executat într-un context diferit de cel al programului
întrerupt, diferenţa fiind legată de modul de tratare, protecţie, informaţiile accesibile, etc.
Nivele de prioritate. Cauzele care duc la necesitatea întreruperii unui procesor sunt
diferite, drept rezultat şi programele predefinite, care tratează întreruperile diferă. Mecanismul
întreruperilor trebuie să poată deosebi aceste cauze. Două scheme de bază sunt utilizate în acest
scop:
Există un indicator unic pentru toate întreruperile şi acestui indicator îi este asociat
un program unic de tratare a întreruperilor. O informaţie suplimentară (codul întreruperii),
care se conţine în cuvântul de stare sau într-un amplasament de memorie, dă posibilitatea de
a deosebi cauzele. Prima obligaţie a programului de tratare a întreruperilor este de a
consulta codul întreruperii pentru a stabili originea acesteia, doar apoi se va trece la tratarea
propriu-zisă.
Fiecărei cauze este ataşat un indicator, se mai spune că fiecare cauză este ataşată
unui nivel de întrerupere. Fiecărui nivel îi corespunde un program distinct de tratare a
întreruperii, activat în mod automat de către mecanismul de comutare a contextului.
Priorităţi şi mascarea întreruperilor. Atunci când există mai multe nivele de întrerupere
este posibilă necesitatea modificării simultane a doi indicatori, legaţi de două cauze diferite.
Conflictul poate fi reglat stabilind o ordine de prioritate în cadrul nivelelor de întrerupere.
Această ordine poate fi fixată odată pentru totdeauna sau modificabilă prin microprogramare.
Adesea este utilă protejarea, contra unor întreruperi anume, a execuţiei unei suite de
instrucţiuni (de exemplu, poate fi interzisă întreruperea unui program de tratare a întreruperii).
Aceasta ar însemna întârzierea comutării contextului, comutare, provocată de sosirea unui
semnal asociat unui nivel oarecare de întrerupere. Se zice atunci, că nivelul este mascat sau
inhibat (întrerupere mascată). Ridicarea inhibării ("demascarea") va autoriza schimbarea
ulterioară a contextului. Informaţiile asociate mascării întreruperilor se află în cuvântul de stare a
procesorului.
Pentru unele nivele de întrerupere efectul sosirii semnalului de întrerupere poate fi suprimat
(nu doar întârziat). Totul se va petrece în acest caz ca şi cum însăşi cauza întreruperii a fost
suprimată: nivelul întreruperii este dezarmat. Un nivel dezarmat poate fi rearmat, adică repus
în serviciu.
Declanşare programată. Pentru unele calculatoare, îndeosebi cele utilizate în controlul
proceselor, există o instrucţiune de declanşare programată care permite modificarea
indicatorului, asociat unui nivel de întrerupere, din interiorul unui program. În acest fel este
posibilă simularea apariţiei unei cauze externe de întrerupere.
Atunci când toate condiţiile necesare pentru ca o întrerupere să fie luată în consideraţie sunt
prezente, nivelul se numeşte activ. Această stare corespunde executării programului de tratare a
întreruperii. Notăm, că această execuţie poate fi suspendată pentru a permite tratarea unei
întreruperi cu o prioritate mai înaltă. Ieşirea din starea activă se face prin achitarea întreruperii.
17
Achitarea este realizată folosind instrucţiunea schimbă_csp, care termină tratarea schimbând
contextul.
Operaţiile de armare, dezarmare, mascare, demascare şi declanşare a întreruperilor sunt
totdeauna realizate prin intermediul unor instrucţiuni privilegiate.
Schema unui program de întrerupere. O întrerupere forţează procesorul să reacţioneze la
un eveniment. Executarea programului curent este suspendată, comanda fiind transmisă
programului de tratare a întreruperii. Programul reluat de către procesor după tratarea întreruperii
nu este în mod obligator programul întrerupt (întreruperea putea avea scopul realocarea
procesorului).
33. Devieri şi apelarea supervizorului
O deviere semnalizează o anomalie în derularea unei instrucţiuni, care prohibitează
executarea instrucţiunii. Originile pot fi diverse:
date incorecte, care conduc la imposibilitatea execuţiei corecte a instrucţiunii
(împărţirea la zero, de exemplu),
tentativa executării unei operaţii interzise de mecanismul de protecţie
(violarea protecţiei memoriei, executarea unei instrucţiuni privilegiate în modul program,
etc.),
instrucţiune neexecutabilă (cod neautorizat de operaţie, adresă în afara
memoriei existente, utilizarea unui dispozitiv opţional, care este lipsă în configuraţia dată,
etc.).
Devierile pot fi clasificate, ca şi întreruperile, conform cauzelor care le generează. Efectul
unor cauze poate fi suprimat (de exemplu devierile legate de operaţiile aritmetice, erorile fiind
semnalate doar de valoarea codului condiţiei). Natura unei devieri nu permite aplicarea
noţiunii de mască. O deviere poate fi suprimată, dar nici intr-un caz retardată.
Un apel al supervizorului (supervisor call, prescurtat SVC, eng., appel au superviseur, fr.)
este o instrucţiune chemată să provoace o comutare a contextului procesorului. Acest efect este
analogic apelării unei proceduri, însă modificarea contextului este mai profundă, fiindcă ea
afectează întreg cuvântul de stare şi nu numai contorul ordinal.
Destinaţia unui apel al supervizorului este de a permite apelarea unei proceduri a sistemului
de operare, pretinzând la drepturi mai mari (modul master, întreruperi mascate, drepturi de acces,
etc.), direct din programul utilizatorului. Mecanismul comutării contextului permite asigurarea
protecţiei, impunând condiţiile de intrare procedurii apelate. Ca rezultat:
contextul nou (modul, masca, etc.,) este specificat în noul cuvânt de stare,
amplasat intr-o zonă de memorie inaccesibilă utilizatorilor,
programul de tratare a apelului supervizorului începe cu o secvenţă de
verificare a drepturilor utilizatorului de a executa acest apel şi stabilirea validităţii
parametrilor transmişi.
Tratarea
întreruperii
Salvarea contextului
programului P
Comutarea cuvântului de
stare
Programul întrerupt
P
Tratarea specifică întreruperii, care presupune
determinarea programului Q pentru lansare (poate fi
chiar P sau altul)
Restabilirea contextului programului
Q încărcarea cuvântului de stare a lui
Q
Instrucţiunea schimbă_csp (achitare)
Programul nou Q
Fig.2.4. Schema generală a tratării unei întreruperi
18
Parametrii sunt transmişi ca şi în cazul apelului unei proceduri obişnuite. Returul în
programul apelant se face prin restabilirea cuvântului de stare salvat la apelare.
Operaţiile de accesare a fişierelor şi de intrare-ieşire sunt disponibile utilizatorilor sub
forma apelării supervizorului.
34. Exemple de sisteme de întreruperi
Funcţionarea sistemelor de întrerupere este ilustrată prin două exemple reprezentative, unul
pentru un calculator mare, altul pentru calculatoarele personale.
Exemplul 2.6. IBM 370.
Cuvântul de stare (64 biţi) conţine următoarele câmpuri:
<0-7> masca întreruperii <16-31> codul întreruperii
<8-11> cheie de protecţie <32-33> lungimea instrucţiunii
<12> codul caracterelor <34-35> codul condiţiei
<13> masca întreruperii <36-39> suprimarea devierii
<14> 1 - aşteptare, 0 - activ <40-63> contor ordinal
<15> 0 - stăpân, 1 - sclav.
Sistemul de întreruperi are 5 nivele (în ordinea de descreştere a priorităţilor): eroare
hardware, deviere, apelare supervizor, extern şi intrare-ieşire. Fiecărui nivel îi corespunde în
memoria operativă un cuplu de amplasamente rezervate cuvintelor de stare vechi şi nou. Fiecare
nivel conţine mai multe cauze de întrerupere. Pentru a face o deosebire a acestor cauze este
utilizat un cod al întreruperii format din biţii 16 - 31 ai cuvântului de stare. Acest cod este în mod
automat pus la zi în cazul unei întreruperi. De exemplu, pentru o întrerupere de intrare-ieşire el
va conţine adresa canalului şi a perifericului care au provocat întreruperea; pentru o întrerupere
externă acest cod permite să se stabilească originea - ceasul, apel al operatorului, adresare a unui
organ extern, etc. Biţii 0 - 7 şi 13 ai cuvântului de stare permit introducerea măştii întreruperii. Ei
permit mascarea nivelelor de întrerupere externă, eroare hardware şi, selectiv, întreruperile de
intrare-ieşire, care provin de la diferite canale. Biţii 36 - 39 permit inhibarea a 4 cauze de
deviere.
Observăm, că devierile şi a apelările supervizorului sunt tratate ca şi întreruperi particulare.
Exemplul 2.7. IBM PC. Este propus ca exerciţiu.
35. IMPLEMENTAREA MECANISMELOR DE COMUTARE A
CONTEXTULUI
Implementarea mecanismelor descrise mai sus este ilustrată printr-o serie de exemple,
legate de utilizarea lor.(intrebarea 6)
Vom preciza notaţia utilizată în schemele programelor:
conţinutul unui cuvânt de stare este reprezentat prin notaţia <activitate, mod,
mascare, contor ordinal>. Primele trei câmpuri pot lua, respectiv, valorile: aşteptare/activ,
master/slave, mascat/demascat. Dacă csp desemnează un cuvânt de stare, câmpurile sale
vor fi desemnate de csp.act, csp.mod, csp.masc şi csp.co.
19
operatorul adr aplicat unui identificator de variabilă sau de procedură,
desemnează adresa amplasamentului unde se află variabila sau prima instrucţiune a
procedurii,
notaţia Mp[adr] desemnează conţinutul amplasamentului cu adresa adr.
Notaţiile svc_vechi, dev_vechi, intr_x_vechi, svc_nou, dev_nou, intr_x_nou
desemnează amplasamentele unde sunt plasate şi de unde sunt încărcate cuvintele de stare.
Vom mai presupune că
apelarea supervizorului este de forma SVC <cod>, unde <cod> reprezintă un
număr care permite identificarea funcţiei cerute,
un indicator <cauză> permite stabilirea cauzei care provoacă o deviere.
Schemele prezentate conţin un program de iniţializare, executat la prima încărcare a
sistemului. Funcţia acestui program este de a iniţializa cuvântul de stare asociat tratării
întreruperilor, devierilor şi apelurilor supervizorului.
36. Utilizarea devierilor şi apelării supervizorului
Simularea instrucţiunilor lipsă. Unele instrucţiuni din setul de bază de instrucţiuni ale
procesorului pot fi opţionale şi, deci, pot lipsi în unele configuraţii ale calculatorului. Tentativa
executării unei instrucţiuni opţionale lipsă generează o drivere de tipul instrucţiune inexistentă.
Mecanismul devierilor poate fi utilizat pentru a realiza prin program instrucţiunea inexistentă în
setul de bază. De exemplu, pentru o configuraţie în care operaţiile aritmetice în virgulă mobilă
nu sunt disponibile ele pot fi simulate prin apelarea procedurilor corespunzătoare. Aceste
proceduri trebuie executate în mod slave pentru a permite tratarea explicită a erorilor: ele sunt
apelate prin încărcarea unui cuvânt de stare. O adresă de retur trebuie să fie pregătită de către
programul de tratare a devierii în top-ul stivei pentru a asigura returul la instrucţiunea care
urmează instrucţiunii de operaţie aritmetică simulată.
Realizarea prin program:
procedura iniţializare;
dev_nou:=<activ,master,mascat, adr tratare_deviere>;
csp[ADD_FL]:= <activ,slave,demascat, adr ADD_FL>;
……
csp [DIV_FL]:= <activ,slave,demascat, adr DIV_FL>;
procedura tratare deviere;
begin
save(zonă);
case cauză of
……
instrucţiune inexistentă:
cod_op:=Mp[dev_vechi.co].cod_operaţie;
case cod_op of
……
20
ADD_FL: determinarea operanzilor;
introdu_în_stivă(stivă_utilizator,dev_vechi.co+1);
încarcă_csp(csp[ADD_FL])
……
else -- caz de eroare
<tratarea erorii>
end;
end;
restabilire(zonă);
încarcă_csp(dev_vechi)
end
Operanzii vor fi determinaţi prin analiza conţinutului instrucţiunii, care conţine adresele lor;
returul rezultatelor utilizează convenţiile proprii instrucţiunii în cauză (plasarea într-un registru,
etc.).
Măsurarea capacităţii memoriei. Un sistem de operare presupune a fi utilizat pentru
diverse configuraţii ale calculatorului. Capacitatea memoriei, numărul şi natura dispozitivelor
periferice, etc., pot fi diferite. Sistemul de operare trebuie să se adapteze configuraţiei concrete,
ca şi condiţiilor particulare de utilizare (număr de utilizatori, priorităţi, etc.). Crearea unei
asemenea versiuni specifice se numeşte generarea sistemului de operare. Pentru a reduce
frecvenţa generărilor S.O. unii parametri de configurare pot fi determinaţi în mod automat la
iniţializare.
Astfel, poate fi determinată capacitatea memoriei operative utilizând o deviere pentru
adresa amplasamentului de memorie inexistent. Memoria constă dintr-un număr nbloc de
blocuri (care trebuie determinat), fiecare bloc conţinând p cuvinte. Un program executat la
iniţializarea sistemului încearcă să acceseze ciclic primul cuvânt al fiecărui bloc; tentativa de
accesare a primului bloc inexistent în configuraţia curentă provoacă, prin deviere, părăsirea
buclei. Numărul de blocuri este egal cu numărul primului bloc neimplantat (blocurile fiind
numerotate începând cu 0).
Realizarea prin program:
program principal:
begin
dev_nou:= <activ,master,mascat, adr măsurare>;
i:=1;
ciclu
<accesare cuvânt cu adresa i.p>;
i:=i+1;
endciclu;
ieşire ciclu: nbloc:=i;
21
dev_nou := <activ,master,mascat, adr tratare_deviere>;
end
procedura măsurare; -- apelare prin deviere
if cauză = adresă în afara memoriei then
csplucrare:= <activ,master,mascat, adr ieşire ciclu>;
încarcă_csp(csplucrare)
endif
La ieşirea din programul de măsurare a capacităţii memoriei se va restabili tratarea normală
a devierilor (procedura tratare_deviere).
Gestionarea devierilor de către utilizatorul sistemului. Reacţia standard la o deviere care
are loc în timpul execuţiei unui program utilizator este apelarea unei proceduri de sistem, care
provoacă emiterea unui mesaj de eroare, oprirea programului curent şi trecerea la programul
următor.
Este de dorit ca fiecare utilizator să aibă posibilitatea să asocieze fiecărei cauze distincte de
deviere i o procedură proprie, tratarea căreia ar înlocui reacţia standard. Pentru a evita o buclă
infinită, o deviere din aceeaşi cauză i în interiorul acestei proceduri trebuie să apeleze procedura
standard.
Asocierea unei proceduri proc de reluare a cauzei i de deviere se face cu ajutorul unui apel
al supervizorului (SVC asociere_deviere) cu parametrii i şi proc.
Pentru trecerea la programul următor se va apela o procedură a sistemului de operare, apel
realizat prin încărcarea unui cuvânt de stare, numit schimbare.
Realizarea prin program:
const ndev=<numărul de cauze de deviere>;
var C: array[0..ndev-1] of boolean;
adrtratare: array[0..ndev-1] of adresă;
procedura iniţializare;
begin
svc_nou:=<activ,master,mascat, adr tratare_svc >;
for i:=0 to ndev-1 do -- tratare standard
C[i]:=false;
endfor;
dev_nou:=<activ,master,mascat, adr tratare_dev >;
end
procedura tratare_svc;
begin
save(zonă);
case cod of
……
22
asociere_deviere: -- parametrii i, proc
C[i]:=true;
adrtratare[i]:=adr proc;
restabilire(zonă);
încarcă_csp(svc_vechi)
……
endcase
end
procedura tratare_dev(i);
begin
save(zonă);
if C[i] then
C[i]:=false; -- restabilire tratare standard
introdu_în_stivă(stivă_utilizator,dev_vechi.co); -- pentru retur
dev_vechi.co:= adrtratare[i];
restabilire(zonă);
încarcă_csp(dev_vechi);
else
<tratare standard[i]>;
încarcă_csp(schimbare); -- programul următor
endif
end
Programul de tratare a devierii, specificat de către utilizator se va executa în modul slave,
iar returul se va face cu ajutorul mecanismului standard de retur dintr-o procedură, deoarece
adresa de retur a fost pusă în vârful stivei de execuţie.
37. Exemple de utilizare a întreruperilor
Principala utilizare a întreruperilor este măsurarea timpului şi administrarea operaţiilor de
intrare-ieşire. Prezentăm mai jos câteva exemple de utilizare a ceasului calculatorului.
Un ceas de calculator este realizat cu ajutorul unui oscilator cu cuarţ, care emite impulsuri
periodice. Perioada de emitere, de obicei poate fi aleasă dintr-o plajă de valori prestabilită, de
exemplu de la 0.1 până la 100 microsecunde. Aceste impulsuri sunt utilizate pentru a decrementa
valoarea unui contor, conţinut într-un registru special sau într-un cuvânt de memorie, rezervat
acestui scop. Când acest contor trece prin zero este declanşată o întrerupere, numită întrerupere
de ceas, care corespunde unui nivel rezervat acestui efect.
Pentru aplicaţiile care urmează vom presupune, că fiecare impuls decrementează cu 1
conţinutul unei locaţiuni de memorie, notat ceas.
23
Limitarea timpului de execuţie a unei proceduri. Este necesar să fie executată o procedură
p astfel, încât dacă după un interval de timp prestabilit q, numit timeout, executarea nu se va
termina, ea va fi întreruptă şi o procedură specificată tratare_eroare este apelată.
Realizarea prin program:
procedura iniţializare;
intr_ceas_nou:=<activ,master,mascat,adr intr_ceas>;
svc_nou :=<activ,master,mascat,adr tratare_svc >;
dezarmare(intr_ceas);
procedura tratare_svc;
save(zonă);
case cod of
…
apel_lim_timp_ex: -- parametrii p, q, tratare_eroare
ceas:=q;
cspretur:=svc_vechi; -- salvare pentru retur
csplucrare:= <activ,slave,demascat,adr p>;
csperoare:= <activ,slave,demascat,adr tratare_eroare>;
armare(intr_ceas);
restabileşte(zonă);
încarcă_csp(csplucrare);
…
retur: -- datorat terminării procedurii p
dezarmare(intr_ceas);
încarcă_csp(cspretur);
…
endcase
procedura intr_ceas; -- expirarea timpului limită
dezarmare(intr_ceas);
încarcă_csp(csperoare);
Primul eveniment, care va avea loc (expirarea timpului q, rezervat executării, sau returul din
p), dezarmează ceasul şi activează procedura adecvată pasându-i contextul curent. Returul din p
trebuie să se facă prin apelarea supervizorului şi nu printr-o instrucţiune obişnuită de retur. La fel
se va proceda şi cu returul din tratare_eroare, dacă se cere revenirea la contextul apelării iniţiale
a procedurii p.
Culegerea unor date de măsurare. Un calculator are obligaţiunea să preia periodic datele
unor măsurări legate de o instalaţie industrială. Perioada ceasului este de 5 μs. Datele trebuie
culese fiecare 100 ms (perioada de eşantionare). Deoarece timpul necesar culegerii datelor este
cu mult inferior perioadei de eşantionare, calculatorul poate executa alte lucrări în regim de fond.
24
Realizarea prin program:
const q = 20000 -- 100ms/5μs
procedura iniţializare;
begin
intr_ceas_nou:=<activ,master,mascat,adr intr_ceas>;
csplucrare:= <activ,slave,demascat,adr fond>;
cspmăsurare:= <activ,slave,demascat,adr măsurare>;
ceas:=q;
încarcă_csp(cspdev)
end
procedura intr_ceas;
begin
save(zonă); salvarea contextului de fond
cspsave:=intr_ceas_vechi; salvarea cuvântului de stare pentru fundal
ceas:=q;
încarcă_csp(cspmăsurare) programul de culegere a datelor
end
Programul de măsurare trebuie să se termine printr-o apelare a supervizorului SVC retur
efectul căreia este de a restabili contextul lucrului în fond. Acest apel execută secvenţa:
restabileşte (zonă);
încarcă_csp(cspsave);
Remarcă. Putem include procedura măsurare direct în programul de tratare a întreruperii,
care ar fi avut în forma
save(zonă);
ceas:=q;
măsurare;
restabileşte(zonă);
încarcă_csp(intr_ceas_vechi)
Dar în acest caz programul de măsurare va trebui să fie executat în modul master şi
întreruperile să fie mascate, ceea ce nu ar permite modificarea sau înlocuirea lui de către un
utilizator neprivilegiat. Această remarcă ilustrează un principiu general, care cere îndeplinirea
independentă (decuplată) a programelor de tratare a întreruperilor (secvenţe de scurtă durată,
executate cu privilegii înalte) şi programele activate de către procedurile de tratare a
întreruperilor şi apelate prin încărcarea unui cuvânt de stare (tratare primară şi secundară a
întreruperii).
Administrarea lucrărilor în timp partajat. O mulţime de programe sau lucrări trebuiesc
executate pe un calculator, utilizând procesorul în regim de partajare a timpului: procesorul este
alocat succesiv lucrărilor într-o ordine prestabilită, pentru tranşe de timp de durată fixă q (cuanta
25
de timp). Dacă o lucrare este încheiată înainte de expirarea cuantei q, procesorul este imediat
alocat lucrării următoare.
Lucrările sunt numerotate de la 0 la n-1. Este definită o zonă de amplasare a cuvântului de
stare a procesorului csp[i] pentru fiecare lucrare i şi o altă zonă reg[i] pentru registrele acesteia.
Aceste zone permit salvarea contextului procesorului de fiecare dată când o lucrare este
întreruptă pentru a permite reluarea ulterioară a lucrării întrerupte.
Realizarea prin program:
Pentru început, presupunem că lucrările nu se vor termina niciodată. Vom utiliza un fir
circular de lucrări, notat fir_lucr şi gestionat de trei proceduri intrare, ieşire şi urm.
procedura iniţializare;
begin
for i:=0 to n-1 do
csp[i] := <activ,slave,demascat,adr lucrare[i]>;
intrare(i, fir_lucr);
endfor
intr_ceas_nou:=<activ,master,mascat,adr intr_ceas>;
svc_nou:=<activ,master,mascat,adr trattare_svc>;
lucr_ales:=0; -- începem cu lucrarea 0
încarcă_csp(csp[lucr_ales]);
end
procedura intr_ceas;
begin
csp[lucr_ales]:=intr_ceas_vechi;
save_registre(reg[lucr_ales]);
lucr_ales:=urm(lucr_ales);
ceas:=q;
încarcă_registre(reg[lucr_ales]);
încarcă_csp(csp[lucr_ales]);
end
Pentru a lua în consideraţie terminarea lucrărilor, fiecare lucrare trebuie să înştiinţeze
sistemul atunci când execuţia sa a luat sfârşit printr-un apel al supervizorului SVC end după cum
este prezentat mai jos.
procedura tratare_svc;
…
case cod of
…
term:
suc:=urm(lucr_ales);
26
ieşire(lucr_ales, fir_lucr);
lucr_ales:=suc;
ceas:=q;
încarcă_registre(reg[lucr_ales]);
încarcă_csp(csp[lucr_ales]);
endcase
Am presupus că firul de lucrări nu va deveni niciodată vid. În practică aceasta poate fi
obţinut prin trecerea la o lucrare de fond, care poate eventual fi redusă la o buclă.
Concluzii
Exemplele precedente ilustrează modurile elementare de comunicare dintre programele unui
sistem de operare şi mediul exterior. Programele sistemului sunt activate:
1) fie de către un program al utilizatorului, care semnalează o anomalie (deviere)
sau cere achitarea unui serviciu (apelarea supervizorului),
2) fie de către un dispozitiv extern (ceas, proces comandat, organ periferic sau
linie de comunicaţii), care semnalează producerea unui eveniment şi care cere o reacţie
imediată a sistemului.
Ca şi rezultat putem afirma că un sistem de operare este pilotat de evenimente (event-
driven, eng.). Notăm de asemenea, că comunicaţia internă între programele unui sistem foloseşte
apelarea supervizorului dacă un anumit tip de protecţie trebuie să fie activat (program executat
în modul slave, de exemplu) şi apelarea unei proceduri obişnuite în caz contrar. O secvenţă de
execuţie a unui program de sistem se termină prin încărcarea unui cuvânt de stare a procesorului
care permite controlul total al contextului restabilit.
38. PROGRAMAREA OPERAŢIILOR DE INTRARE-IEŞIRE
Prin noţiunea de intrare-ieşire (prescurtat I/E; eng. input/output, I/O; fr. entrée-sortie, E/S)
numim orice transfer de informaţii din sau spre nucleul calculatorului. Operaţiile de I/E
semnifică:
transferurile de informaţii dintre diferite nivele ierarhice ale memoriei,
transferurile de informaţii din sau spre mediul exterior (organe periferice
locale sau la distanţă, captoare sau dispozitive de acţionare, alte calculatoare, etc.).
39. Organizarea general
Periferice, controlere, canale
Un organ de intrare-ieşire este un dispozitiv capabil să transfere informaţii între procesorul
sau memoria calculatorului şi un suport extern de informaţie. Acest transfer este comandat de
către procesorul central. În cel mai simplu caz, o instrucţiune specială a procesorului permite
transferarea informaţiei între suportul extern şi un registru al procesorului, care va fi deci ocupat
pe toată perioadă transferului informaţiei. Odată cu evoluţia calculatoarelor, în scopul unei mai
bune utilizări a procesorului s-a ajuns la necesitatea acordării unei autonomii organelor de
intrare-ieşire încredinţându-le funcţii tot mai complicate de înlănţuire şi comandă, procesorului
central lăsându-i-se doar iniţiativa de lansare şi de control a operaţiilor. Din considerente
27
economice mai apoi s-a trecut la separarea dispozitivelor de comandă a perifericelor de
perifericele propriu-zise, pentru ca dispozitivele de comandă să poată fi partajate între mai multe
periferice.
Câteva scheme de organizare a perifericelor sunt prezentate în fig.2.5. Schema (c) este
proprie unui calculator de putere mare, (a) şi (b) corespund configuraţiilor calculatoarelor de
putere mai mică. Precizăm funcţiile organelor reprezentate în această figură.
1) Un canal (sau unitate de schimb) este un procesor specializat în operaţiile de
intrare-ieşire. El poate fi lansat doar de un procesor central, nu posedă întreruperi, dar
poate întrerupe un procesor central. Setul de instrucţiuni ale canalului îi permite să
acţioneze controlerele şi perifericele, care-i sunt conectate. Mini- şi microcalculatoarele
pot poseda organe, numite Unităţi de acces direct la memorie (ADM), care sunt nişte
canale simplificate.
2) Un contróler este un dispozitiv de comandă adaptat la un tip concret de
echipament periferic. Autonomia sa este limitată de operaţii foarte elementare. Destinaţia
principală a unui controler este de a permite conectarea a mai multor periferice de acelaşi
tip la un singur controler. Un singur dispozitiv periferic poate transmite informaţii prin
intermediul controlerului la un moment de timp dat. În acelaşi timp, este posibilă
executarea simultană a unor operaţii pe alte periferice, operaţii care nu implică transferul
de informaţii (rebobinarea unei bande magnetice, deplasarea braţului unui disc, etc.).
Partajarea funcţiilor între periferic şi controler depinde de tipul perifericului. De obicei,
funcţiile logice (înlănţuirea şi sincronizarea operaţiilor, emiterea unor semnale în caz de
accident sau terminarea normală a execuţiei) sunt încredinţate controlerului, iar funcţiile
fizice (transferul propriu-zis) - perifericului. În programarea intrărilor-ieşirilor nu este
necesar, de obicei, să se facă o deosebire între un controler şi un periferic.
3) Un periferic este un organ capabil să transfere informaţii din sau spre un
suport extern. Controlerul este legat de periferic printr-o interfaţă, care conţine un set de
funcţii (intrare, ieşire, semnalizări de comandă şi de accident) şi o linie de comunicaţie,
care serveşte la transferul informaţiilor.
UC
M
ADM
Magistrală
Cp
p
Cp
p
UC
M
Cp
p
Cp
p
Magistrală
(a) (b)
M
C C
Magistrală
UC UC
UC : unitate centrală
28
Un canal poate comanda un singur dispozitiv periferic cu debit ridicat (disc, de ex.) sau
poate fi multiplexat pentru mai multe periferice cu debitul mai mic. Încercarea mai multor
procesoare (unităţi centrale sau canale) de a accesa simultan memoria operativă poate genera
conflicte. Conflictele sunt reglate de către dispozitivul hardware de accesare, care impune o
ordine de acces conform unor priorităţi prestabilite. Canalele au prioritate faţă de unităţile
centrale, deoarece ele trebuie să reacţioneze cât se poate de rapid la evenimentele externe.
2.4.1.2. Adresarea dispozitivelor periferice
Diferite organe sunt desemnate, la fiecare nivel, printr-o adresă care permite să
evidenţiem:
canale legate de memorie,
controlere ataşate fiecărui canal,
dispozitive periferice ataşate fiecărui controler.
La un nivel anume adresa este un simplu număr de ordine. Un periferic este
desemnat printr-o adresă compusă
<numărul canalului, numărul controlerului, numărul dispozitivului
periferic>.
Un controler poate fi conectat la mai multe canale, iar un periferic la mai multe controlere,
care vor fi, obligator, de acelaşi tip. Astfel, un periferic are mai multe căi de acces la memorie
(doar una singură poate fi activă la un moment de timp dat) şi poate fi desemnat prin mai multe
adrese (fig.2.6).
29
Această organizare permite ameliorarea performanţelor şi disponibilităţii sistemului.
Existenţa mai multor căi de acces la un periferic diminuează riscul unor indisponibilităţi din
cauza saturaţiei sau ieşirii din funcţiune a unui canal sau controler.
În cazul unor calculatoare, cum ar fi de exemplu DEC, adresarea perifericelor utilizează
amplasamente de memorie rezervate, care sunt asociate cuvântului de stare sau registrului de
date a unui controler specificat. Accesarea cuvântului de stare sau a registrului de date este
realizată prin intermediul instrucţiunilor obişnuite de accesare a memoriei. Această schemă
simplifică desemnarea perifericelor şi programarea intrărilor-ieşirilor.
40. Metode de comandă a perifericelor
Programul, care controlează funcţionarea elementară a unui dispozitiv periferic se numeşte
driver. Driverul gestionează în mod direct interfaţa controlerului perifericului, tratează
întreruperile generate de acesta, detectează şi tratează cazurile de eroare. El este, de obicei,
invizibil unui utilizator obişnuit al sistemului, care apelează funcţii de intrare-ieşire prin
intermediul unor servicii de înalt nivel, realizate prin apelări ale supervizorului. Vom prezenta
mai jos modurile principale de control ale perifericelor şi primitivele elementare de intrare-ieşire.
Intrări-ieşiri sincrone
În acest caz nu există nici un fel de paralelism între procesare şi transferul informaţiilor.
Procesorul este ocupat pentru toată durata transferului.
Schema care urmează nu descrie doar un caz particular, ci este reprezentativă pentru
organizarea intrărilor-ieşirilor sincrone pentru mai multe tipuri de calculatoare.
1) Specificarea mecanismului
11
01, 10
00
1
0
1
0
1
0
1
0
1
0
1
0
Canal
Canal
Controler
Controler
Controler p
p
p
p
p
001
000
111
011
101
010
100
Fig.2.6. Adresarea perifericelor
30
Operaţia de bază constă în transferarea unor informaţii elementare de volum fix între un
amplasament de memorie şi un dispozitiv periferic. Presupunem că volumul informaţiei
transmise, care depinde de perifericul considerat, este un octet. Starea ansamblului controler-
periferic este definită printr-un cuvânt de stare, aflat în controler. Acest cuvânt de stare conţine o
mulţime de indicatori booleeni, dintre care doar 3 ne vor interesa aici:
preg : perifericul este pregătit (gata) de funcţionare, detaliile legate de
stabilirea indicatorului depind de periferic,
term : transferul este terminat; perifericul este gata să transfere un nou
caracter,
err : în cursul transferului a avut loc o eroare; natura ei este
precizată de un cod care face parte din cuvântul de stare.
Controlerul este comandat de unitatea centrală cu ajutorul a trei instrucţiuni de intrare-
ieşire, efectul cărora este descris mai jos:
IN(adr_mem, adr_perif) : cerere de transfer tip intoducere a
unui octet,
OUT(adr_mem, adr_perif) : cerere de transfer tip extragere
a unui octet,
TEST(adr_perif) : copie cuvântul de stare într-un registru cu
scopul de a consulta indicatorii.
Prin adr_mem şi adr_perif sunt desemnate adresele amplasamentului memoriei şi
perifericului.
2) Programul driver-ului
Fie că vrem să extragem o secvenţă de n caractere care se află într-un masiv T[0..n-1].
Caracterul T[i], dacă i>0, poate fi extras doar dacă a fost transferat T[i-1]. Pentru a verifica
această condiţie se testează iterativ (aşteptare activă) un indicator term.
iniţializare : term:=false;
TEST(adr_perif);
if nonpreg then
<tratare eroare>
endif;
31
for i:=0 to n-1 do
OUT(adr T[i],adr_perif);
ciclu : TEST(adr_perif);
if err then
<tratare eroare>
endif;
if nonterm then goto ciclu
endif;
endfor
Intrările-ieşirile sincrone sunt folosite la microprocesoarele cele mai simple sau atunci
când procesorul nu poate fi exploatat în mod util în timpul transferului (înregistrări de măsurare,
încărcarea iniţială a unui sistem).
Intrări-ieşiri asincrone cu întreruperi
1) Specificarea mecanismului.
Terminarea procesului de transferare a caracterului T[i] este semnalizată printr-o
întrerupere. Dacă acest caracter nu este ultimul (i<n-1), următorul caracter poate fi transmis.
Procesul este declanşat de transferul primului caracter. Acest transfer este cerut de către
programul principal prin intermediul unui apel a supervizorului (SVC intrare sau ieşire), care are
drept parametri:
adresa perifericului,
numărul de caractere care vor fi transferate,
adresa de origine sau de destinaţie a primului caracter,
un boolean term, valoarea TRUE a căruia semnalizează sfârşitul transferului.
Programul principal programul de
tratare a întreruperii
term:=FALSE (la părăsirea lui T[i])
SVC i:=0;
32
ieşire OUT(adr T[i], adr_perif);
save context;
TEST(adr_perif);
… if err then
<tratare eroare>
else
if i<n-1 then
<tratare paralelă> i:=i+1;
OUT(adr T[i], adr_perif)
… else
term:=TRUE
if term then endif
… endif;
<restabilire context>
2.4.2.3. Intrări-ieşiri programate pe canal sau acces direct la memorie
41. Intrări-ieşiri buferizate în memorie
Specificarea problemei
Diferenţa considerabilă dintre viteza de lucru a unităţii centrale şi cea a organelor
periferice impune "buferizarea" intrărilor-ieşirilor, adică introducerea unei zone de memorie-
tampon între periferic şi programul utilizatorului. Scopul este de a reduce timpul de inactivitate a
unităţii centrale, dezlegând funcţionarea acesteia de periferice. Programul utilizatorului va
transfera informaţiile din sau spre zona-tampon, iar această zonă-tampon va servi, în mod
paralel, drept sursă sau destinaţie la schimbul de date cu perifericul. Dezlegarea unităţii centrale
de periferic este cu atât mai bine realizată cu cât este mai mare capacitatea zonei-tampon.
Adesea, pentru a nu supraîncărca memoria principală, zona-tampon este situată pe discul fix.
Pentru descrierea modelului sunt necesare următoarele specificaţii:
schimburile de informaţii cu perifericele se va face prin înregistrări de
lungime fixă,
33
zona-tampon este de volum fix egal cu N înregistrări,
pentru un program utilizator, schimbul de informaţii cu zona-tampon trebuie
să simuleze schimbul cu perifericul, drept consecinţă, ordinea de depozitare sau de
extragere a informaţiilor trebuie să fie bine stabilită şi nici o înregistrare să nu fie pierdută,
aşteptările inutile trebuie reduse la minimum, atât în cazul unităţii centrale,
cât şi a perifericului,
capacitatea suporturilor nu este limitată: în cazul unei operaţii de citire
organul de intrare va fi totdeauna alimentat; în cazul unei operaţii de scriere, organul de
ieşire poate accepta întotdeauna o înregistrare,
transferul se va efectua fără eroare.
Descrierea algoritmilor
1) Citire
Un program de citire este o procedură citire(înregistrare), care prezintă drept rezultat
valoarea înregistrării citite. Această procedură, realizată printr-o apelare a supervizorului, are ca
efect citirea din zona-tampon a înregistrării următoare. Citirea este posibilă doar dacă zona-
tampon conţine cel puţin o înregistrare, care nu a fost încă citită. În caz contrar, activitatea
apelantă trece în starea de aşteptare. În ambele cazuri, continuitatea alimentării zonei-tampon
este asigurată de citirea unei înregistrări de la perifericul de intrare, dacă un transfer nu are deja
loc.
Terminarea transferului unei înregistrări în zona-tampon provoacă o întrerupere. Pentru a
menţine perifericul în stare activă, programul de tratare asociat acestei întreruperi trebuie să
relanseze transferul următor, dacă mai există loc în zona-tampon. Plus la aceasta, dacă activitatea
apelantă era în aşteptarea sosirii unei înregistrări, ea trebuie relansată.
Acest mod de funcţionare poate fi schematic prezentat conform schemei programului de
mai jos.
periferic de
intrare
programul
utilizator citire (înreg)
Zonă-tampon cu N
locaţiuni
34
procedura citire(înreg) tratare
întrerupere
(apelare supervizor)
if tamponul_nu este_vid then if
tamponul_nu este_plin then
extragere(înreg, tampon);
lansare_transfer;
lansare_transfer în caz de necesitate; if
aşteptare then // aşteptare pentru citire
else reluare citire
lansare_transfer în caz de necesitate; endif
aşteptare
endif
În acest program "în caz de necesitate" semnifică "dacă un transfer nu este deja în curs".
Sistemul este iniţializat de citirea primei înregistrări, care provoacă transferuri succesive până la
umplerea zonei-tampon.
2) Scriere
Schema care corespunde unei scrieri se obţine din precedenta, înlocuind după cum
urmează:
citire prin scriere
extragere prin introducere
tampon_vid prin tampon_plin
tampon_plin prin tampon_vid
periferic
de ieşire
programul
utilizator scriere (înreg)
Zonă-tampon cu N
locaţiuni
35
procedura scriere(înreg) tratare
întrerupere
(apelare supervizor)
if tamponul_nu este_plin then if
tamponul_nu este_vid then
introducere(înreg, tampon);
lansare_transfer;
lansare_transfer în caz de necesitate; if
aşteptare then
else reluare scriere
lansare_transfer în caz de necesitate; endif
aşteptare
endif
3) Programe
Programele sunt o transcriere a schemelor de mai sus. Zona-tampon este un fir de
aşteptare, gestionat circular cu ajutorul a doi pointeri: tcitire (top-ul FA) - indică următoarea
înregistrare care urmează a fi preluată, qcitire (coada FA) - indică amplasamentul unde se va
introduce următoarea înregistrare. Funcţia suc realizează înlănţuirea amplasamentelor; o realizare
simplă pentru o zonă-tampon secvenţială, care are N înregistrări a câte L amplasamente este de
forma:
suc(ptr) = (ptr + L) mod (L.N)
Vom presupune, că activitatea care cere operaţia citire este unica care va utiliza
procesorul; trecerea acesteia în starea de aşteptare se va realiza trecând în starea de aşteptare
procesorul. Această soluţie este impracticabilă în cazul unor activităţi multiple (este necesar de a
relansa o altă activitate), dar o vom accepta din motive de simplitate.
Mai subliniem că transferul este comandat de un canal sau un ADM, fără a detalia
programul respectiv, pregătit de obicei anticipat; numai valorile parametrilor se vor schimba de
36
la o execuţie la alta. Procedurile lansare_citire şi lansare_imprimare realizează pregătirea
programului şi lansarea transferului.
Variabil
e
Semnificaţie Valoare iniţială
L lungimea unei casete
(înregistrări)
const.
Ncitire numărul de casete a zonei-
tampon
const
nvcitire numărul de casete vide Ncitire
citire_a
ctiv
indicator al activităţii
perifericului de intrare
false
tcitire,
qcitire
pointeri top şi coadă 0, 0
suc() pointer spre caseta următoare …
citire(în
reg)
tratare_întrerupere_
perif_de_intrare
save(zonă_svc); save(zonă_întrerupere);
început: qcitire:=suc(qcitire);
if nvcitir<Ncitire then nvcitire:=nvcitire-
1;
periferic
de intrare
programul
utilizator (SVC) citire (înreg)
Zonă-
tampon
qcitire tcitire
37
înreg:=tampon[tcitire]; if nvcitire>0 then
tcitire:=suc(tcitire);
lansare_perif_de_intrare(qcitire)
nvcitire:=nvcitire+1; else
if non citire_activ then
citire_activ:=false
citire_activ:=true; endif;
lansare_perif_de_intrare(qcitire) if
aşteptare_citire then
endif întrerupere_veche.act:=activ;
else aşteptare_citire:=false
if non citire_activ then endif;
citire_activ:=true;
restabilire(zonă_întrerupere);
lansare_perif_de_intrare(qcitire)
încărcare_csp(întrerupere_veche);
endif;
csplucrare:=<aşteptare,slave,demascat, adr început>;
lansare_perif_de_intrare(qcitire)
aşteptare_citire:=true; elaborare prog.canal:
încărcare_csp(csplucrare); <sens=citire
endif; adr.memorie=adr tampon[qcitire]
restabilire(zonă_svc); contor_octeţi=L>
încărcare_csp(svc_vechi); SIO
<prog=prog.canal
perif= perif_de_intrare>
38
Execuţia programelor de mai sus ne impun să facem o remarcă foarte importantă. Trebuie
să notăm, că executarea tratării întreruperii este declanşată de sfârşitul transferului fizic al unei
înregistrări, activitate, care are loc paralel cu executarea programului primitivei citire(înreg) pe
procesor. Drept rezultat, este posibil ca întreruperea să survină într-un punct oarecare
(observabil) al executării acestei primitive, ceea ce va însemna intercalarea executării
programului de tratare a întreruperii între două puncte oarecare ale programului citire(înreg).
Consecinţele pot fi catastrofale, cum ne arată exemplul următor.
Să considerăm instrucţiunea a doua
if non citire_activ then
citire_activ:=true;
lansare_perif_de_intrare(qcitire)
endif
din programul citire(înreg). Ea se descompune în următoarele instrucţiuni elementare:
(a) load R, citire_activ
(b) jifz R, urm -- ramificare dacă true
(c) …
urm: …
<aşteptare>
Presupunem că întreruperea soseşte între instrucţiunile (a) şi (b), valoarea citită în R de (a)
este true; programul de tratare a întreruperii pune citire_activ în false. După prelucrarea
întreruperii, instrucţiunea (b) este executată cu R având valoarea true şi activitatea apelantă trece
în starea de aşteptare în care rămâne un timp indefinit, deoarece perifericul nu a fost relansat. Pot
exista şi alte cazuri de funcţionare incorectă, legată de momentul sosirii unei întreruperi.
Putem afirma, că validitatea variabilelor comune (de ex. citire_activ, nvcitire etc.,) nu
poate fi garantată dacă autorizăm sosirea întreruperilor de terminare a operaţiilor de intrare-ieşire
în orice moment de timp. Apelarea supervizorului pentru a realiza secvenţa de cod citire_înreg
trebuie executată cu întreruperile de intrare-ieşire mascate. Situaţia dată este cunoscută sub
numele de excludere mutuală şi este o consecinţă a execuţiei activităţilor asincrone.
Programele pentru un periferic de ieşire (imprimare, de ex.) sunt analogice. Remarca
despre mascarea întreruperilor rămâne valabilă.
39
Variabil
e
Semnificaţie Valoare iniţială
L lungimea unei casete
(înregistrări)
const.
Nimp numărul de casete a zonei-
tampon
const
nvimp numărul de casete vide Nimp
imp_act
iv
indicator al activităţii
perifericului de intrare
false
timp,
qimp
pointeri top şi coadă 0, 0
suc() pointer spre caseta următoare …
scriere(î
nreg)
tratare_întrerupere_
imp
save(zonă_svc); save(zonă_întrerupere);
început: qimp:=suc(qimp);
if nvimp>0 then nvimp:=nvimp+1;
imprimant
ă
programul
utilizator (SVC) scriere (înreg)
Zonă-
tampon
timp qimp
40
tampon[timp]:= înreg; if nvimp<Nimp
then
timp:=suc(timp); lansare_imp(qimp)
nvimp:=nvimp-1; else
if non imp_activ then
imp_activ:=false
imp_activ:=true; endif;
lansare_imp(qimp) if aşteptare_imp then
endif întrerupere_veche.act:=activ;
else aşteptare_imp:=false
if non imp_activ then endif;
imp_activ:=true;
restabilire(zonă_întrerupere);
lansare_imp(qimp)
încărcare_csp(întrerupere_veche);
endif;
csplucrare:= :=<aşteptare,slave,demascat, adr început>; lansare_imp(qimp)
aşteptare_imp:=true; elaborare prog.canal:
încărcare_csp(csplucrare); <sens=ieşire
endif; adr.memorie=adr tampon[qimp]
restabilire(zonă_svc); contor_octeţi=L>
încărcare_csp(svc_vechi); SIO
<prog=prog.canal
perif= imprimantă>
42. Încărcarea iniţială
41
Pentru a începe lucrul maşina "goală" trebuie să aibă încărcat în memoria operativă
programul sistemului de operare şi să execute un salt la prima instrucţiune a acestui program.
Aceasta presupune prezenţa în memorie a unui program de citire, care el însuşi trebuie încărcat
în prealabil. La primele calculatoare, un program de câteva instrucţiuni, introdus manual în
memorie cu ajutorul unor comutatoare ale pupitrului de comandă la o adresă fixă, permitea
încărcarea unui program de citire mai elevat capabil să citească versiunea completă a sistemului
de operare. Acest proces era numit încărcare (bootstrapping, eng.).
În calculatoarele contemporane, programul de iniţializare se află permanent într-o
memorie constantă (BIOS). Execuţia acestui program este declanşată odată cu punerea sub
tensiune a calculatorului (autoîncărcare).
43. Gestionarea activităţilor paralele. Exemple introductive
Reluăm exemplul imprimării cu gestionarea unor zone tampon pe disc
Sau
Comanda unui proces industrial
Mai jos sint descrise
44. Administrarea tamponată a intrărilor-ieşirelor
Reluăm exemplul imprimării cu gestionarea unor zone tampon pe disc, descris în capitolul
2. Analiza acestui mod de funcţionare (fig.3.1) pune în evidenţă patru activităţi, care pot avea loc
simultan:
1) primitiva scriere_linie SL (unitatea centrală)
2) scriere pe disc SD (canal 1)
3) citire de pe disc CD (canal 2)
4) imprimare fizică IF (canal 3)
În realitate, citirea şi scrierea pe disc sunt executate pe acelaşi canal, ceea ce poate impune unele restricţii privind simultaneitatea executării lor. Vom ignora aici aceste
restricţii, justificând mai apoi acest mod de procedare.
scriere_linie
(memorie) (memorie)
Fig.3.1. Gestionarea buferizată a unei
imprimante
tm1
td
tm2
SD IF CD
(disc)
SL
42
Aceste patru activităţi sunt în mare măsură autonome, or ele sunt executate pe procesoare
distincte, cu programe diferite. Ele nu sunt totuşi independente, deoarece accesează obiecte
comune: două tampoane în memorie, tm1 şi tm2 şi un tampon pe disc, td. Pot fi evidenţiate două
tipuri de condiţii, care trebuie respectate:
Condiţii, care stabilesc posibilitatea existenţei unor activităţi
O înregistrare nu poate fi preluată dintr-un tampon înainte de a nu fi depozitată aici.
Tampoanele au capacităţi limitate; dacă un tampon este ocupat cu înregistrări, care nu au fost
încă preluate, este imposibilă depozitarea fără a pierde informaţii. Acţiunile de depozitare şi
preluare sunt, deci, supuse unor condiţii de posibilitate de existenţă, enumerate mai jos.
Activita
te
Acţiune Condiţie
SL scriere
în tm1
tm1 nu
este plin
SD citire
din tm1
tm1 nu
este vid
SD scriere
în td
td nu este
plin
CD citire
din td
td nu este
vid
CD scriere
în tm2
tm2 nu
este plin
IF citire
din tm2
tm2 nu
este vid
Execuţia activităţilor modifică veridicitatea acestor condiţii: astfel, imprimarea unei linii
pune în TRUE condiţia “tm2 nu este plin”.
O activitate, care nu poate executa o acţiune, deoarece condiţia asociată are valoare FALSE,
trebuie să aştepte, adică execuţia unei acţiuni este retardată până când valoarea logică a condiţiei
43
devine TRUE. În capitolul 2 a fost discutată realizarea acestui mecanism de aşteptare şi
continuare cu ajutorul întreruperilor.
Condiţii de validitate a informaţiilor partajate
Dacă vom examina procesul de accesare a tampoanelor, vom descoperi o altă formă de
interacţiune, cauzată de posibilitatea de accesare simultană de către două activităţi a unui
amplsament de memorie. Astfel, dacă SD citeşte conţinutul unei înregistrări din tm1 pe care SL
este în curs de a o modifica, rezultatul acestei citiri riscă să fie incoerent, dacă nu au fost luate
măsuri speciale de precauţie. Problema poate fi rezolvată impunând una din activităţi, aflate în
conflict, să “aştepte” până când cealaltă va termina accesarea.
Concluziile acestei prime analize:
Lucrarea “imprimare tamponată” este realizată prin patru activităţi simultane, în mare
măsură autonome, care cooperează pentru atingerea scopului final.
Executarea corectă a lucrării impune restricţii logice în vederea derulării acestor activităţi.
Aceste restricţii pot conduce la întârzierea execuţiei unei activităţi, care este obligată să aştepte
producerea unui eveniment, provocat de o altă activitate.
45.Comanda unui proces industrial
Să reluăm exemplul din capitolul 1, în care un calculator comandă un reactor
chimic. Considerăm două reactoare identice, R1 şi R2, care funcţionează în paralel. Vom examina
două soluţii posibile:
1) utilizarea a două calculatoare (câte unul pentru fiecare reactor),
2) folosirea unui singur calculator pentru comanda ambelor reactoare.
Prima variantă nu prezintă nimic nou în raport cu descrierea din capitolul 1. Soluţia a doua
cere stabilirea condiţiilor suplimentare pentru realizarea sa. Implementarea variantei doi impune
verificarea posibilităţii apariţiei unor condiţii suplimentare. Fie P1, P2, D1, D2 segmentele
procedurilor şi datelor pentru comanda celor două reactoare R1 şi R2, memoria principală având
capacitatea necesară pentru păstrarea acestor segmente. Programele P1 şi P2 sunt executate pe
rând de procesor. Raţionând ca şi în capitolul 1, concluzionăm că relaţia 2t<T trebuie să fie
respectată. Dacă acesta va fi cazul, funcţionarea reactoarelor pentru un observator extern pare
identică pentru ambele soluţii. Trebuie, totuşi să subliniem, că soluţia doi impune restricţii mai
severe în ceea ce priveşte performanţele calculatorului (capacitatea memoriei şi viteza de
procesare)
Vom examina mai jos modalităţile de implementare a soluţiei doi.
1) Partajarea procesorului
44
Între două execuţii succesive ale lui P1, procesorul este utilizat de P2, ca rezultat starea sa
internă (conţinutul registrelor, cuvântul de stare, contorul ordinal) va fi modificată. Pentru a
permite reluarea lui P1, informaţiile sale trebuiesc salvate la terminarea fiecărei secvenţe de
execuţie şi restabilite la începerea execuţiei următoare. Aceleaşi afirmaţii sunt valabile şi în cazul
executării lui P2.
2) Partajarea programului
Programele P1 şi P2, fiind identice, putem păstra doar o singură copie, să-i zicem P, pentru
economisirea memoriei. Să examinăm condiţiile necesare pentru partajarea programului P:
nu este permisă modificarea codului programului de execuţia sa,
atunci când P este executat pentru reactorul Ri (i=1 sau 2), el va accesa segmentul
de date Di; această adresare selectivă a datelor va fi realizată de un mecanism care nu
modifică textul programului.
Un program, existent în exemplar unic, dar care poate fi utilizat pentru executarea mai
multor activităţi independente, eventual simultane, se numeşte program reentrant
(reenterabil). Acest mod de utilizare implică:
invarianţa textului programului în cursul executării sale,
desemnarea uniformă, de către program, a datelor proprii fiecărei activităţi.
Printre altele, dacă activităţile partajează un procesor unic, informaţiile despre starea
acestuia (în particular, cele care servesc la desemnarea datelor) trebuiesc salvate la fiecare
comutare.
Să rezumăm rezultatele celui de-al doilea exemplu.
1. Au fost evidenţiate două activităţi logic independente: comanda reactoarelor
R1 şi R2. Aceste două activităţi pot fi puse pe două maşini distincte fără să existe vre-o
legătură între ele.
2. Considerente de economie pot impune ca aceste activităţi să partajeze resurse
fizice şi resurse program comune. Buna funcţionare a acestei partajări restricţionează
execuţia activităţilor (utilizarea alternativă a procesorului) şi modul de utilizare a
obiectelor partajate (salvarea contextului de executare, reentranţa programelor).
Ca şi concluzie pentru ambele exemple putem evidenţia două momente:
existenţa unor activităţi evolutive, care pot derula simultan,
existenţa unor relaţii între aceste activităţi: cooperare pentru executarea unor
sarcini comune, concurenţă în utilizarea resurselor partajate. Aceste relaţii sunt
determinate de specificaţiile de “bună funcţionare”. Ele se pot traduce în restricţii de
execuţie, care conduc la întârzieri temporare a progresării unei activităţi.
Continuarea acestui capitol are drept scop elaborarea unui suport formal pentru aceste
noţiuni, introducând conceptele de proces şi sincronizare şi descriind modalităţile lor de
utilizare în cadrul unui sistem informatic.
46.Noţiune de proces secvenţial
45
Noţiunea de proces este mai întâi introdusă într-un mod concret pentru cazul unui
calculator care conţine un procesor unic şi o memorie adresabilă. Vom trece mai apoi la
definiţia abstractă a unui proces independent de suportul său fizic, ceea ce ne va permite
introducerea problemei sincronizării.
47.Proces unic. Context
Noţiunea de proces pune la dispoziţie un model pentru reprezentarea unei activităţi, care
rezultă din executarea unui program pe calculator. Starea calculatorului este definită de starea
procesorului (conţinutul registrelor) şi starea memoriei (conţinutul amplasamentelor). Această
stare este modificată de către procesor prin executarea instrucţiunilor programului. Fiecare
executare a unei instrucţiuni constituie o acţiune: o acţiune are ca efect trecerea în timp finit a
calculatorului dintr-o stare iniţială într-o stare finală. Acest efect este descris în specificaţiile
instrucţiunii.
Executarea unei instrucţiuni va fi considerată indivizibilă sau atomară, adică este interzisă
observarea sau definirea stării maşinii în timpul acestei execuţii. Timpul utilizat pentru
descrierea evoluţiei stării este un parametru t, care poate lua o serie de valori discrete
crescătoare, corespunzătoare începutului şi sfârşitului instrucţiunilor. Aceste instanţe sunt
numite puncte de observare, iar stările corespunzătoare ale maşinii sunt numite puncte
observabile. Prin abuz de limbaj, acest ultim termen desemnează în egală măsură şi punctele de
observare. Acestea permit să se asocieze o dată (valoarea curentă a lui t) unei stări a maşinii; o
atare stare datată defineşte un eveniment. Evenimentele permit reperarea modificărilor stării
maşinii. Începutul şi sfârşitul unei acţiuni a sunt evenimente datele cărora sunt notate început(a)
şi sfârşit(a); vom avea, evident, început(a)<sfârşit(a).
Executarea unui program se traduce, deci, într-o suită de acţiuni a1, a2,..., ai,..., cu
început(ai)<sfârşit(ai).
O astfel de suită este numită proces secvenţial (sau simplu proces).
Un proces poate, deci, fi descris cu ajutorul succesiunii evenimentelor început(a1),
sfârşit(a1), început(a2), sfârşit(a2),... Această suită de stări datate ale maşinii se numeşte
traiectorie temporală (sau istorie) a procesului. Putem de asemenea defini un proces ca o suită
de activităţi în sensul lui 2.1.
Mulţimea informaţiilor pe care acţiunile unui proces le pot consulta sau modifica se
numeşte contextul procesului. Reluând modelul de execuţie secvenţială introdus în 2.1,
contextul unui proces rezultant din executarea unui program conţine:
1) Contextul procesorului (cuvântul de stare şi registrele),
2) Un context în memorie, sau spaţiul de lucru (segmente procedură, date, stivă
de execuţie),
3) O mulţime de atribute ataşate procesului şi care specifică diferite proprietăţi:
Într-un mod mai riguros ar trebui să adăugăm aici “punctele întreruptible” care pot fi prezente în unele instrucţiuni de lungă durată; o executare a unei asemenea
instrucţiuni poate fi considerată o suită de mai multe acţiuni.
Pentru comoditatea expunerii considerăm, că sfârşitul unei acţiuni şi începutul acţiunii următoare sunt două evenimente distincte, datele cărora sunt diferite, deşi stările
corespunzătoare sunt identice.
46
a) Nume. Numele unui proces, care serveşte pentru identificarea lui, este de
regulă, un număr intern atribuit la crearea procesului şi care permite să se ajungă la
reprezentarea contextului său (v.4.2).
b) Prioritate. Prioritatea proceselor permite ordonarea lor pentru alocarea
procesorului (v.4.2, 4.3). Dacă toate procesele au aceeaşi prioritate, alocarea se face
conform ordinii “primul sosit, primul servit”.
c) Drepturi. Drepturile unui proces specifică operaţiile care îi sunt permise, în
scopul asigurării protecţiei informaţiei (v. 5.1.4).
Traiectoria temporală a unui proces este definită de şirul stărilor contextului său
(procesor şi memorie) preluate după execuţia fiecărei instrucţiuni. Prin definiţie, starea restului
maşinii nu este modificată de execuţia procesului.
48.Relaţii între procese
Vom cerceta în continuare execuţia unei mulţimi de procese şi interacţiunea
reciprocă a acestora. Noţiunile, introduse în 3.2.1 pot fi extinse pentru o mulţime de procese:
traiectoria temporală a unei mulţimi de procese este şirul evenimentelor formate de
începuturile şi sfârşiturile acţiunilor rezultante din executarea programelor acestor procese.
contextele unor procese diferite pot avea părţi comune. Două procese, contextele
cărora sunt disjuncte, se numesc independente; ele nu pot avea interacţiuni reciproce.
Partea contextului, care aparţine unui singur proces, se numeşte context privat al
procesului dat.
Exemplul 3.1. Fie două procese care partajează o procedură reentrantă.
Segmentul executabil, care conţine această procedură aparţine contextului comun.
Segmentul de date şi stiva fiecărui proces formează contextul lor privat. ◄
49.Mulţimi de procese. Paralelism
Să considerăm două programe distincte P şi Q, fiecare având în memorie un segment cod şi
un segment de date. Numim p şi q procesele rezultante din executarea respectivă a acestor două
programe. Executarea setului (p, q) poate să se producă în diferite moduri, caracterizate de forma
particulară a traiectoriei sale temporale. Aceste traiectorii sunt reprezentate în figura 3.2.
Schemele de mai sus pot fi comentate astfel:
schema 1: este executat mai întâi tot procesul p, apoi procesul q la fel în întregime,
schema 2: sunt executate şiruri de instrucţiuni ale procesului p în mod alternativ cu
şiruri de instrucţiuni ale procesului q, şi tot aşa până la terminarea ambelor procese,
schema 3: executarea proceselor p şi q este simultană; în acest caz sunt necesare
două procesoare.
Pentru compararea acestor scheme de execuţie introducem noţiunea nivel de observare.
Putem considera o suită de acţiuni ale unui proces ca o acţiune unică, adică să observăm
derularea unui proces considerând o unitate de execuţie
47
mai puţin fină decât instrucţiunea. De exemplu, dacă vom redefini noţiunea de acţiune
elementară ca execuţie a unei proceduri, traiectoria procesului va conţine doar stările definite de
fiecare apel şi retur de procedură. Nivelul de observare cel mai fin (cel al instrucţiunilor) este
numit nivel de bază.
Să ne situăm mai întâi la nivelul de observare la care, prin convenţie, executarea completă a
fiecărei dintre programele P şi Q reprezintă o acţiune unică. Definiţiile care urmează sunt pentru
acest nivel.
a) schema de tip 1 este a unei execuţii secvenţiale a lui p şi q. Ea este caracterizată de
relaţiile:
sfârşit(q) < început(p) sau sfârşit(p) < început(q)
b) schemele de tip 2 sau 3 sunt scheme de execuţie paralelă. Ele sunt
caracterizate de
sfârşit(p) > început(q) sau sfârşit(q) > început(p).
Revenim la nivelul de bază. Putem face o distincţie între schemele 2 şi 3. Într-adevăr, în
schema 2, din considerente de existenţă a unui singur procesor, la un moment de timp dat doar o
singură acţiune poate fi executată, contrar schemei 3. Se va spune că în schema 3 are loc un
paralelism real, iar în schema 2 – un pseudo-paralelism. Paralelismul real necesită două
procesoare distincte. Două observaţii importante sunt necesare:
1) Diferenţa acestor scheme de execuţie este legată de alegerea nivelului de
observare. Astfel, la nivelul de bază, diferenţa dintre schemele 1 şi 2 dispare: ambele sunt
secvenţiale.
Exemplu 3.2. Utilizatorii unui sistem de operare, care funcţionează în timp
partajat pe un singur procesor, au impresia că programele lor sunt executate în mod
paralel, deoarece nivelul lor de observare este cel al comenzilor limbajului de
comandă, compuse din multe instrucţiuni. La nivelul de bază, însă, aceste instrucţiuni
sunt atomare şi executate de procesor în mod secvenţial. Exemplul celor două
reactoare chimice, prezentate în 3.1.2, conduce la observaţii analogice. ◄
2) Alegerea nivelului de bază depinde de fineţea fenomenelor, care dorim să le
considerăm elementare. Dacă trebuie să studiem executarea instrucţiunilor în “pipe-line” pe
un procesor microprogramat, în calitate de nivel de bază va fi ales nivelul
(1)
(2)
(3)
p q
p q
p q p q p q
Fig. 3.2. Executarea unei mulţimi de
procese
48
microinstrucţiunilor, iar contextul va fi completat cu memoria microprogramelor şi
registrele interne.
Vom examina realizarea, la nivelul de bază, a unei scheme de execuţie de tipul 2. La fiecare
realocare a procesorului, contextul procesului curent trebuie salvat, pentru a permite reluarea
ulterioară a acestei execuţii. Dacă memoria are o capacitate suficientă pentru a păstra toate
segmentele, doar contextul procesorului trebuie salvat. Dacă memoria principală poate conţine,
la un moment de timp dat, doar segmentul procedură şi datele unui singur proces, aceste
segmente de asemenea trebuie salvate pe disc. Această remarcă justifică definiţia operaţională,
adesea întâlnită, a contextului unui proces ca mulţime a informaţiilor care trebuie salvată
pentru a permite reluarea ulterioară a procesului, dacă execuţia acestuia a fost întreruptă.
50.Concurenţa proceselor. Resurse virtual
Situaţia descrisă de schemele 1 şi 2 nu rezultă dintr-o legătură logică între p şi q, ci doar din
existenţa unui singur procesor. Ea poate fi caracterizată astfel: fie o mulţime de procese
contextele cărora au un obiect comun, care poate fi utilizat la un moment de timp dat de un
singur proces. Se va spune în acest caz, că obiectul constituie o resursă critică pentru procesele
date sau că procesele sunt în excludere mutuală (excludere reciprocă sau concurenţă) pentru
utilizarea unei resurse. În situaţia descrisă, procesorul este o resursă critică pentru procesele p şi
q.
Observăm că excluderea mutuală a unei resurse conduce la “serializarea” execuţiei
proceselor concurente, în cazul unor acţiuni, care cer această resursă (în exemplul dat, toate
acţiunile). Schemele 1 şi 2 diferă doar prin nivelul de fineţe la care este executată serializarea.
Funcţionarea corectă a unei mulţimi de procese, care participă la îndeplinirea unei lucrări
comune, implică relaţii logice de cooperare (v.3.1.1). Este comod să se separe această cooperare
de concurenţa pentru resursele fizice cu scopul de a simplifica înţelegerea şi aplicarea celor două
tipuri de relaţii. Pentru aceasta este folosită noţiunea de resurse virtuale: fiecărei resurse fizice
critice i se asociază tot atâtea copii imaginare (sau virtuale) ale acestei resurse câte procese
concurente solicită utilizarea ei. Suntem nevoiţi să tratăm două probleme distincte:
1) respectarea relaţiilor de cooperare între procesele, care, fiecare posedă
(conceptual) resursele fizice solicitate şi pentru care paralelismul în execuţie nu este
restricţionat de competiţia pentru resurse,
2) reglarea problemei de concurenţă pentru resursele fizice printr-o serializare
convenabilă a execuţiei proceselor în cauză. Se va spune în acest caz, că realizăm o alocare
a resurselor fizice.
Introducerea resurselor virtuale are o consecinţă foarte importantă pe care o vom ilustra-o
prin exemplul proceselor p şi q, definite în 3.2.2.1. Să ataşăm fiecărui proces un procesor virtual.
Conceptual, totul va avea loc ca şi cum procesele s-ar derula paralel, conform unei scheme,
numite logice sau virtuale, analogice schemei 3 din fig.3.2. Cu toate acestea, trebuie de
menţionat, că această schemă logică reprezintă doar o notaţie compactă pentru mulţimea
schemelor reale posibile şi că ele sunt obligatoriu de forma 1 sau 2 din considerentele unicităţii
49
procesorului. Pentru o schemă reală şi una virtuală a unui proces dat este păstrată doar ordinea de
succesiune a evenimentelor (începutul şi sfârşitul acţiunii) şi nu sunt păstrate valorile absolute
ale intervalelor de timp, care le separă. În absenţa altor informaţii, nu putem spune nimic apriori
despre ordinea evenimentelor, asociate unor procese distincte. Timpul folosit la reperarea
evenimentelor în schema logică este numit timp logic; relaţiile sale cu timpul real sunt
prezentate în fig.3.3. a1 a2 +------+-----------------+------+ procesul p b1 b2 (timp logic) +--+-------+---------+ procesul q
a1 a2
+------+---+ +----------+ +----+------+ p (timp real, execuţia
1)
+--+--+ +-----+---------+ q
b1 b2
a1 a2
+---+ +---+-----------------+------+ p (timp real, execuţia
2)
+--+----+ +---+---------+ q
b1 b2
În toate cazurile a1 precede a2, b1 precede b2.
Fig.3.3. Timpul logic şi timpul real
Vom considera, că evoluţia proceselor are loc în timp logic, adică vor fi interzise orice
ipoteze despre viteza relativă a proceselor în cauză: aceasta este consecinţa simplificării
considerabile, introduse de noţiunea de resurse virtuale, care permite ignorarea mecanismelor de
alocare. O singură excepţie, totuşi va fi făcută pentru studierea sincronizării temporale, în care
timpul fizic intervine în mod precis ca măsură a duratei şi nu numai ca mod de reperare relativă.
50
51. Excludere mutual 51
52. Sincronizarea proceselor 51
53. Exprimarea şi implementarea restricţiilor de precedare 51-52
54. Probleme de realizare a sincronizării 52
55. Monitorul – mecanism de sincronizare. Definiţii. Ex. 53
56. Implementarea sincronizării. Probleme-tip 53
57. Administrarea unei resurse partajate 54
58. Alocarea resurselor banalizate 54
59. Modelul cititorului şi redactorului 55
60. Comunicarea între procese 55
61. Modelul producătorului şi consumatorului 56
62. Primitive de comunicare 57
63. Aplicaţii : relaţia client-server 58
64. Administrarea intrărilor-ieşirilor 59
65. Administrarea unui periferic 59
66. Buferizarea imprimării 60
67. Sincronizare temporală 61
68. Gestionarea dinamică a proceselor 63
69. Sincronizarea în Windows 65
70. Procese şi fire 65
71. Necesitatea sincronizării 66
72. Structura mecanismului de sincronizare în Windows 67
73. Administrarea obiectelor de sincronizare în Windows 67
74. Excluderea mutual 68
75.Evenimentele 68
51
51. Excludere mutual (3.2.2.1)
Fie o mulţime de procese contextele cărora au un obiect comun, care poate fi utilizat la un
moment de timp dat de un singur proces. Se va spune în acest caz, că obiectul constituie o resursă
critică pentru procesele date sau că procesele sunt în excludere mutuală (excludere reciprocă
sau concurenţă) pentru utilizarea unei resurse. În situaţia descrisă, procesorul este o resursă critică
pentru procesele p şi q.
52. Sincronizarea proceselor (cap. 3)
Sincronizarea reprezintă derularea concomitentă (se petrec în acelaş timp) a proceselor ce
folosesc resurse commune, de obicei un hardware device sau o mulțime de variabile. Sincronizarea
îşi propune 4 acţiuni cheie:
accesarea de către o mulţime de procese a unei resurse partajate
comune,
comunicarea între procese,
gestionarea perifericelor şi intrărilor-ieşirilor tamponate,
sincronizare temporală.
53. Exprimarea şi implementarea restricţiilor de precedare (3.3.1)
(1)
(2)
(3)
p q
p q
p q p q p q
Fig. 3.2. Executarea unei mulţimi de procese
52
Exemplul 3.4. Procesul p transmite informaţii procesului q scriind într-un
segment a, consultat de q (se presupune că această transmitere are loc o singură dată).
Este necesar să se verifice condiţia: sfârşit(scriere(a)) < început(citire(a))
Această relaţie exprimă restricţia, că citirea lui a de către q nu poate începe înainte de
terminarea scrierii lui a de către p.
Restricţiile de sincronizare pot fi exprimate prin următoarele două forme echivalente:
1. Se va impune o ordine de succesiune în timp logic pentru unele puncte ale
traiectoriei temporale ale procesului,
2. Se va impune unor procese o condiţie de autorizare a depăşirii acestor puncte
ale traiectoriei lor temporale.
Punctele privilegiate astfel se vor numi puncte de sincronizare. Expresia (2) arată, că
restricţiile de sincronizare pot fi satisfăcute impunând un proces “să aştepte” să execute o acţiune
până când o oarecare condiţie va fi satisfăcută. Această noţiune de aşteptare nu poate fi exprimată
cu ajutorul instrumentarului introdus până acum; pentru aceasta vom introduce o nouă stare pentru
un proces, stare în care procesul se zice în aşteptare sau blocat, prin opoziţie stării activ,
considerate până acum în mod implicit. Se numeşte blocare tranziţia activaşteptare şi
deblocare tranziţia inversă. Specificarea proceselor se va produce în două etape:
1) definirea punctelor de sincronizare pentru fiecare proces,
2) asocierea unei condiţii de depăşire fiecărui punct de sincronizare, condiţie
exprimată prin intermediul variabilelor de stare a sistemului.
54. Probleme de realizare a sincronizării
Exemplul 3.8 sincronizare a proceselor p si q. var e : eveniment memorizat;
procesul p procesul q
scriere(a); <debut_q>;
e:=sosit; aşteptare(e);
<continuare_p> citire(a)
Implementarea condiţiilor de sincronizare nu poate fi corect realizată numai cu ajutorul
operaţiilor de aşteptare. Consultarea şi modificarea variabilelor de stare, care intervin în aceste
condiţii, trebuie să fie executate în regim de excludere reciprocă. Observaţia dată ne impune să
introducem un mecanism de sincronizare, care în mod automat ar asigura acest regim de
funcţionare (e vorba de monitor).
53
procedura debut_citire;
if non fact then
term.aşteptare
endif
begin -- iniţializare
fact := false
end
end sinc
55. Monitorul – mecanism de sincronizare. Definiţii. Exemple de utilizare (3.3.3)
Un monitor este o metodă de sincronizare a două sau mai multe sarcini ce folosesc o resursă
comună, de obicei un hardware device sau o mulțime de variabile. În concurența bazată pe
monitor, compilatorul sau interpretorul introduce cod, în mod transparent, pentru blocarea sau
deblocarea unor proceduri specificate, fără a fi nevoie ca programatorul să acceseze explicit
primitive de sincronizare. Un monitor este constituit dintr-o mulţime de variabile de stare şi o
mulţime de proceduri. Monitorul poate fi utilizat doar prin apelarea procedurilor sale externe;
acestea permit blocarea sau deblocarea proceselor conform specificaţiilor problemei. Condiţiile de
blocare sau deblocare sunt exprimate ca funcţie ale variabilelor de stare, iar mecanismul de
execuţie a monitorului garantează manipularea acestor variabile în regim de excludere mutuală. În
fine, un monitor conţine un fragment de cod de iniţializare, executat o singură dată la crearea
monitorului.
Exemplul de utilizare 3.10. sinc: monitor;
var fact: boolean;
term: condiţie;
procedura terminare_scriere;
begin
fact:=true;
term.semnalizare
end
56. Implementarea sincronizării. Probleme-tip (3.4.1)
Experienţa demonstrează, că problemele de sincronizare logică întâlnite în practică pot fi
reduse, în marea lor majoritate, la combinaţia unui număr mic de situaţii elementare, schemele de
soluţionare ale cărora sunt cunoscute. Secţiunile 3.4.2 – 3.4.5 sunt consacrate studierii acestor
probleme-tip, utilizând instrumentarul de bază, pus la dispoziţie de monitoare. Problemele-tip sunt
următoarele:
54
accesarea de către o mulţime de procese a unei resurse partajate
comune,
comunicarea între procese,
gestionarea perifericelor şi intrărilor-ieşirilor tamponate,
sincronizare temporală.
57. Administrarea unei resurse partajate (3.4.2)
Considerăm o resursă (fizică sau logică) partajată de o mulţime de procese. Utilizarea acestei
resurse trebuie să respecte nişte reguli de utilizare sau restricţii de integritate, pentru fiecare
resursă. O modalitate de garantare a respectării regulilor de utilizare a unei resurse constă în
adoptarea următoarei scheme:
modul de folosire a resursei presupune utilizarea obligatorie a
procedurilor de acces asociate resursei; orice tentativă de utilizare, care nu respectă acest
mod este detectată automat,
procedurile de accesare sunt grupate într-un monitor, sau mai
multe, programul căruia impune respectarea restricţiilor de integritate.
Cel mai simplu caz este acela al unei resurse pentru care singura restricţie de integritate este
de a fi utilizată în excludere reciprocă. Simpla grupare a procedurilor sale de acces într-un monitor
unic garantează respectarea acestor restricţii.
58. Alocarea resurselor banalizate (3.4.2.1)
Considerăm o resursă pentru care există un număr fix de N exemplare. Un proces poate
accesa la cerere n unităţi din cele N, le poate utiliza şi apoi elibera. O unitate, folosită de un proces,
se numeşte alocată procesului, care o utilizează, pentru toată perioada de la accesare până la
eliberare. Toate unităţile sunt echivalente din punctul de vedere al proceselor utilizatoare, vom mai
zice că resursa este banalizată. Zonele-tampon din memoria principală sau pe disc, unităţile de
bandă magnetică, etc. sunt exemple de resurse banalizate.
Vom admite următoarele reguli de utilizare:
o unitate poate fi alocată la un moment de timp dat doar unui
singur proces,
o unitate poate fi alocată unui proces, care cere alocarea, doar
dacă ea este liberă (ne alocată de alt proces),
operaţia de eliberare este aplicată mereu ultimelor resurse,
obţinute de procesul care execută eliberarea,
55
o cerere de alocare este blocantă în caz de eşec (număr
insuficient de unităţi libere).
59. Modelul cititorului şi redactorului (3.4.2.2)
Să considerăm un fişier manipulat de procese din două clase diferite: cititori (read-only) şi
scriitori (read-write). Fie pentru un moment arbitrar de timp ncit şi nscr numărul de cititori şi de
scriitori. Definim restricţiile:
(nscr=0) şi (ncit0) -- fişier în citire
sau (nscr =1) şi (ncit=0) -- fişier în scriere
Fie fich un monitor care asigură respectarea acestor restricţii. Impunem următoarea formă a
acceselor la fişier:
proces cititor proces scriitor
fich.debut_citire; fich.debut_scriere;
<acces citire> <acces scriere>
fich.terminare_citire; fich.terminare_scriere;
Procedurile debut_citire, terminare_citire, debut_scriere, terminare_scriere trebuie să
asigure respectarea restricţiilor de mai sus. Vom implementa aceste restricţii autorizând depăşirile;
pentru aceasta este necesar să fie precizate priorităţile între cititori şi scriitori.
Exemplu, presupunem că cititorii au prioritate în faţa
redactorilor (o scriere nu va fi autorizată, dacă există cititori în aşteptare). Definim
următoarele variabile de stare:
scr = o scriere este în curs (valoare booleană)
nc = numărul de cititori în aşteptare sau în curs de citire
În acest caz, condiţiile de depăşire se vor exprima după cum urmează:
aut(citire) : scr=false (nu există scrieri curente)
aut(scriere): scr=false şi nc=0 (nici scrieri nici citiri în curs, nici cititori
în aşteptarea)
60. Comunicarea între procese (3.4.3)
56
Procesele pot comunica prin accesarea unei mulţimi de variabile comune. Acest mod de
comunicare este slab structurat şi ineficace, deoarece el trebuie să asigure excluderea reciprocă a
variabilelor. Este utilizat doar în cazuri speciale, cum ar fi un nucleu de sincronizare, unde
excluderea mutuală globală este redusă la secvenţe scurte şi bine protejate. Pentru cazuri generale
sunt utilizate alte moduri de comunicare.
Exemple: a) o schemă de bază pentru comunicarea prin mesaje - modelul producătorului şi
consumatorului, realizat cu ajutorul monitoarelor. b) O altă posibilitate, constă în a considera
operaţiile de comunicare ca un fel de mecanisme primitive de sincronizare. c) o aplicaţie frecventă
de comunicare – modelul client-server.
61. Modelul producătorului şi consumatorului (3.4.3.1)
O schemă uzuală de comunicare este cea în care un proces (producătorul) trimite mesaje
unui alt proces (consumatorul), utilizând un tampon (monitorul) în memoria comună. Mesajele
sunt de lungime fixă şi capacitatea tamponului este de N mesaje. Specificaţiile comunicaţiei sunt
următoarele:
un mesaj dat poate fi preluat doar o singură dată după ce a fost
depozitat în tampon,
un mesaj nu poate fi pierdut; dacă tamponul conţine N mesaje
nepreluate, nu pot fi depozitate aici altele
o operaţie “imposibilă” (depozitare într-un tampon plin /
preluare dintr-un tampon vid) blochează procesul, care încearcă să o execute.
Condiţiile de depăşire pot fi exprimate după cum urmează, notând prin n numărul de mesaje
din tampon, care nu au fost încă preluate:
aut(depozitare) : n < N -- tamponul nu este plin
aut(preluare) : n > 0 -- tamponul nu este vid
Respectarea acestor restricţii este asigurată de un monitor tampon, utilizat după cum urmează:
proces producător proces consumator
... ...
produce(mesaj_emis); tampon.preluare(mesaj_recepţionat);
tampon.depozitare(mesaj_emis); consumator(mesaj_recepţionat);
57
62. Primitive de comunicare (3.4.3.2)
Schimbul de mesaje între procese, în afară de funcţia de transmitere a informaţiei, poate fi
utilizat şi pentru ordonarea evenimentelor în cadrul unor procese distincte, deoarece emiterea unui
mesaj precede întotdeauna recepţia sa. Operaţiile de schimb de mesaje pot fi definite ca nişte
mecanisme primitive şi să le utilizăm pentru sincronizarea proceselor. Primitivele de bază în
comunicarea prin mesaje sunt: emitere(mesaj,destinaţie) şi recepţie(mesaj,origine). Specificările
acestor primitive trebuie să precizeze:
natura şi forma mesajelor,
modul de adresare a proceselor emiţătoare şi destinatare,
modul de sincronizare a acestor procese,
tratarea erorilor.
1) Natura mesajelor
Lungimea poate fi constantă sau variabilă. Mai frecvent sunt utilizate mesajele de lungime
constantă, care pot fi create mai simplu, mesajele de lungime variabilă vor fi transmise prin
referinţă, pasând adresa fizică sau identificatorul informaţiei transmise.
2) Modul de adresare
Procesele, care fac schimb de mesaje, se pot desemna reciproc prin numele lor (desemnare
directă) sau pot utiliza numele unui obiect intermediar ori cutie poştală (desemnare indirectă).
Aceste nume sunt folosite ca parametri origine şi destinaţie.
În cazul desemnării directe parametrul origine a primitivei recepţie poate fi interpretat în
două moduri:
fie ca dată: receptorul specifică explicit că aşteaptă un mesaj de
la un destinatar special (recepţie selectivă),
fie ca rezultat: receptorul primeşte un mesaj care i-a fost
adresat împreună cu identitatea emiţătorului.
În cazul desemnării indirecte asocierea proceselor cutiilor poştale poate fi statică sau
dinamică. În ultimul caz, sunt utilizate două primitive conectare şi deconectare pentru ataşarea
procesului la o cutie poştală (în calitate de receptor) şi de abrogare a acestei ataşări, respectiv. În
unele sisteme un receptor sau mai multe pot fi ataşate unei cutii poştale date; cutiile poştale supuse
unor asemenea restricţii sunt adesea numite porţi.
3) Moduri de sincronizare
În caz general, avem două moduri de sincronizare:
58
Schema producător-consumator, în care cutia poştală este
realizată printr-o zonă tampon. Emiterea nu este blocantă, cu excepţia cazului în care
tamponul este plin.
Schema rendez-vous, în care emiţătorul este blocat până la
preluarea mesajului de către receptor. Această schemă poate fi considerată caz limită a
precedentei cu lungimea nulă a tamponului.
În fine, atunci când un proces este asociat în recepţie la mai multe porţi, poate fi definit un
mod de sincronizare, zis aşteptare multiplă, în care sosirea unui mesaj la o oarecare din aceste
porţi deblochează receptorul.
4) Tratarea erorilor
Scopul tratării erorilor este de a evita blocările infinite ale proceselor, care se pot produce în
diverse circumstanţe:
Emiterea unui mesaj cu o destinaţie (proces sau poartă)
inexistentă. În acest caz primitiva nu este blocantă; eroarea este tratată prin emiterea unui
cod de eroare sau printr-o deviere.
Distrugerea unui proces de la care alte procese aşteaptă un
mesaj sau un răspuns: procesele în aşteptare sunt blocate şi recepţionează un cod de eroare.
63. Aplicaţii: relaţia client-server (3.4.3.3)
O aplicaţie curentă a comunicărilor între procese este relaţia client-server. Un proces server
are în şarjă îndeplinirea unor servicii (executarea unui program predefinit) proceselor client.
Pentru aceasta poate fi utilizată următoarea schemă:
procesul server procesul client
ciclu poartă_serviciu.emitere(cerere)
poartă_serviciu.recepţionare(cerere)
<executare serviciu> ...
[poartă_client.emitere(rezultat)] ...
endciclu [poartă_client.recepţionarere(rezultat)]
Procesul server este asociat unei porţi, unde clienţii îşi depun cererile, trimiţând cereri; el este
blocat atâta timp cât nu există cereri de servicii în aşteptare.
59
Serviciul cerut poate conţine trimiterea la client a rezultatului. În acest caz clientul trebuie să
trimită serverului în cererea sa numărul unei porţi la care el se va bloca în aşteptarea rezultatului.
64. Administrarea intrărilor-ieşirilor (3.4.4)
Vezi întrebările nr. 44, 65 şi 66.
65. Administrarea unui periferic (3.4.4.1)
Fiecărui periferic îi este asociat un monitor procedurile externe ale căruia permit executarea
intrărilor-ieşirilor la acest periferic. Acest monitor are următoarea formă generală (pentru un
sistem mono-utilizator):
perif: monitor; var ..., sfr_schimb_i,...: condiţie;
<declaraţiile variabilelor de stare ale perifericului>
...
procedura schimb_i(<parametri>);
begin
<mascarea întreruperilor>;
if starea ≠ preg then
<tratare eroare(perifericul nu este gata)>
endif;
lansare_transfer_i(parametri);
sfr_schimb_i.aşteptare; -- întrerupere demascată
if starea ≠ ok then -- în timpul aşteptării
<tratare eroare(incident de transfer)>
endif;
<demascare întreruperi>
end;
...
60
begin
<iniţializare>
end
end perif
Procedura lansare_transfer_i pregăteşte programul pentru schimbul cerut şi lansează execuţia
sa. Procesele apelante aşteaptă sfârşitul transferului datorită condiţiei sfr_schimb_i. Sosirea unei
întreruperi, care marchează sfârşitul schimbului de tip i provoacă în mod automat executarea
următoarei secvenţe:
if sfr_schimb_i.vid then <tratarea eroare întrerupere care nu este aşteptată>
else sfr_schimb_i.semnalizare
endif
Pentru un proces care execută o intrare-ieşire apelând o procedură de schimb a acestui
monitor, totul se petrece ca şi cum schimbul este sincron: la returul din procedură, informaţia a
fost efectiv transferată (sau o eroare a fost detectată şi semnalizată). Mecanismul de blocare evită
aşteptarea activă şi procesorul poate fi utilizat în timpul transferului de un alt proces.
66. Buferizarea imprimării
Avem nevoie de trei tampoane tm1 şi tm2 de capacitate N1 şi N2 în memoria centrală şi unul
pe disc, td, de lungime Ndisc. Pentru simplitate presupunem că transferurile se fac cu blocuri
constante egale cu o linie. Fiecare tampon este comandat de un monitor cu aceeaşi structură care
are rolul de a asigura excluderea mutuală şi sincronizarea condiţiilor tampon plin şi tampon vid.
Definind pointerii top şi coadă locali fiecărui monitor, procedurile de depozitare şi preluare pot fi:
<pentru tamponul 1> <pentru tamponul 2>
procedura intrare(l:linie); procedura intrare(l:linie);
tm1[coadă] := l; tm2[coadă] := l;
coadă := coadă+1 mod N1 coadă := coadă+1 mod N2
procedura ieşire(var l:linie); procedura ieşire(var l:linie);
l := tm1[top]; l := tm2[top];
61
top := top+1 mod N1 top := top+1 mod N2
În monitorul tampon_disc operaţiile de depozitare şi preluare sunt intrări-ieşiri ce utilizează
mon. de gestionare a discului:
procedura intrare(l:linie); procedura ieşire(var l:linie);
disc.scriere(l,td[coadă]); disc.scriere(l,td[top]);
coadă := coadă+1 mod Ndisc top := top+1 mod Ndisc
Programul de intrare-ieşire este realizat prin cooperarea a patru procese programul cărora este
prezentat schematic mai jos (trei procese ale sistemului de operare şi procesul utilizator). Pentru a
simplifica expunerea au fost omise secvenţele de tratare a erorilor şi am admis, că sistemul
funcţionează în regim permanent fără limitarea numărului de linii la imprimare. Programele
folosesc trei monitoare de gestionare a perifericelor (tampon1, tampon2 şi tampon_disc) şi două
monitoare de gestionare a perifericelor (impr şi disc), construite în baza modelului perif.
proces imprimare linie proces scriere_disc proces citire_disc
ciclu ciclu ciclu
tampon2.preluare(l); tampon1.preluare(l);
tampon_disc.citire(l);
impr.scriere(l); tampon_disc.scriere(l);
tampon2.depozitare(l);
endciclu endciclu endciclu
Imprimarea unei linii este cerută de procedura:
procedura scriere_linie(l:linie);
tampon1.depozitare(l)
Programele de mai sus sunt mult mai simple decât cele care folosesc direct întreruperile.
Structura modulară, introdusă de monitoare permite separarea totală a gestionării tampoanelor de
cea a perifericelor. Schimbarea capacităţii unui tampon modifică doar monitorul care comandă
acest tampon; înlocuirea unui periferic cu un altul implică rescrierea doar a monitorului, care
comandă acest periferic.
67. Sincronizare temporal (3.4.5)
62
Sincronizarea temporală face ca timpul să intervină nu numai ca mijloc de ordonare a
evenimentelor, dar şi ca măsură de durată absolută. Acest mod de sincronizare este utilizat în
aplicaţiile de timp real, care conţin interacţiuni cu organe externe (comanda proceselor industriale,
de exemplu). Sincronizarea temporală solicită folosirea unui ceas, realizat prin intermediul unui
oscilator cu quartz, care emite impulsuri la intervale regulate. Aceste impulsuri pot fi utilizate
pentru a declanşa o întrerupere la fiecare impuls sau pentru a decrementa în mod automat
conţinutul unui registru contor, o întrerupere este declanşată atunci când conţinutul acestui registru
atinge valoare 0.
valoarea absolută a timpului (ora absolută),
măsoară la orice moment timpul trecut de la o instanţă iniţială,
un registru, adică o listă a proceselor care
aşteaptă deblocarea, ordonat conform timpului absolut de deblocare.
Toate procesele, care apelează primitiva suspendare(t) (folosită pentru blocarea ceasul pe
durată t) sunt inserate în registru în poziţia, care corespunde orei sale absolute de deblocare.
Numim ora_de_bază ora absolută a ultimei înnoiri a ceasului, adică a ultimei iniţializări a
contorului; fie t_aşt ultima valoare încărcată. Ora absolută exactă este dată la fiecare moment de
timp de relaţia
ora_exactă = ora_de_bază + t_aşt - contor
(t_aşt - contor este timpul care s-a scurs după ultima înnoire a contorului). De la o întrerupere
de ceas (la trecerea contorului prin 0), după ultima înnoire s-a scurs un timp egal cu t_aşt;
ora_de_bază poate, deci, fi iniţializată conform relaţiei
ora_de_bază := ora_de_bază + t_aşt
Variabila ora_de_bază, odată iniţializată, va fi corect întreţinută cu condiţia ca registrul să nu
fie nicicând vid; în caz general această condiţie va fi asigurată introducând un proces, numit
paznic:
procesul paznic
ciclu
suspendare(tmax)
endciclu
în care tmax este un interval foarte mare de timp, paznicul rămânând pentru toată perioada de
lucru în coada registrului.
63
Mecanismele descrise sunt realizate într-un monitor numit ceas, care are două intrări:
procedura suspendare (apelată prin ceas.suspendare(t)) şi procedura tratare_întrerupere, pentru
tratarea întreruperii de ceas (trecerea contorului prin zero). Registrul este realizat cu ajutorul unui
fir de aşteptare, care conţine descriptorii proceselor. Un descriptor este format din numele
procesului şi timpul absolut de deblocare; firul de aşteptare este ordonat în ordinea creşterii
timpului deblocării.
68. Gestionarea dinamică a proceselor (3.5)
În sistemele concurente, mai ales în cele interactive, procesele sunt comandate dinamic.
Exemple: în Multics, un proces nou este creat odată cu admiterea unui nou utilizator; în Unix, la
executarea fiecărei comenzi. Crearea unui proces presupune alocarea resurselor şi iniţializarea
contextului. Distrugerea unui proces eliberează toate resursele care i-au fost alocate.
Primele primitive, propuse pentru gestionarea dinamică a proceselor, au fost fork şi join.
Aceste operaţii au fost introduse pentru organizarea executării paralele a programelor pe un sistem
multiprocesoral, noţiunea de proces nefiind încă clară. Vom descrie câteva variante ale acestor
primitive. Fie P o procedură. Instrucţiunea
id := fork(p),
executată de un proces p (părinte), crează un proces nou q (fiul), care va fi executat paralel cu
p. Primitiva fork prezintă ca rezultat identificatorul lui q (sau nil, dacă crearea este imposibilă).
Contextul iniţial al lui q este o copie a lui p, mai puţin contorul ordinal, care este fixat la prima
instrucţiune a lui p. Procesul fiu se termină cu o primitivă, numită exit sau quit, care provoacă
dispariţia sa. După ce fork crează un proces fiu q, primitiva join q permite procesului părinte să
fixeze un punct de rendez-vous cu acest fiu. Executarea lui join q blochează procesul părinte până
când q nu va executa exit. Primitivele fork şi join au avantajele şi dezavantajele instrucţiunii go to
din programarea secvenţială.
Exemplul 3.15. În sistemul de operare Unix crearea unui proces poate fi realizată
de către interpretorul limbajului de comandă (shell) sau cu ajutorul instrucţiunii fork() de
un program. Ultima situaţie este prezentată schematic în fig.3.4.
64
Efectul instrucţiunii fork():
duplicarea procesului părinte;
returnarea valorii pid (numărului procesului fiu) în procesul părinte;
returnarea valorii 0 în procesul fiu:
procesul părinte procesul fiu
if (fork() == 0) if (fork() == 0)
codul procesului fiu codul procesului fiu
else else
codul procesului părinte codul procesului părinte
returnarea pid al procesului fiu ( 0) returnare 0
Altfel spus, în Unix primitiva fork (fără parametri) creează un proces al cărui spaţiu
de lucru este o copie a spaţiului de lucru a creatorului, inclusiv şi contorul ordinal.
Diferenţa poate fi determinată consultând valoarea returnată de primitivă (0 pentru fiu;
identificatorul fiului sau nil pentru părinte). O primitivă wait permite părintelui să
aştepte terminarea execuţiei unuia dintre programele fiu (fără a putea alege care anume,
dacă există mai multe). Un proces termină execuţia sa cu primitiva exit. Primitiva
exec(p) permite unui proces să schimbe contextul, apelând o procedură specificată de p.
La lansarea Unix-ului sunt create două procese: procesul numit Swaper, care
administrează memoria, cu pid=0 şi procesul Init cu pid=1, care creează toate celelalte
procese.
Ilustrăm folosirea primitivelor fork şi exec:
...
id := fork();
procesul 1
copie
date date
stivă
procesul părinte procesul fiu
procesul 2
stivă
Fig.4.4. Crearea proceselor cu ajutorul instrucţiunii fork
65
if id = 0 then -- eu sunt fiul
exec(p) -- programul fiului
else -- eu sunt părintele
if id = -1 then -- nil : creare imposibilă
<tratare eroare>
else
<programul părintelui>
endif
endif
Primitiva wait este utilizată după cum urmează:
id := wait(cod) -- blocare până la terminarea programului unuia dintre fii
... -- id = numărul programului fiu terminat, cod = cauza
terminării
69. Sincronizarea în Windows (3.6)
Platforma pe 32 de biţi pune la dispoziţia programatorului instrumente evoluate pentru
multiprogramare, atât la nivelul unei mulţimi de lucrări, cât şi a unei lucrări singulare. Poate să
apară întrebarea CÂND să fie utilizată multiprogramarea în cadrul unei singure aplicaţii.
Răspunsul este foarte simplu: atunci când dorim ca mai multe fragmente de cod să fie executate
simultan (pseudosimultan, dacă există mai multe fragmente decât procesoare). De exemplu,
dacă dorim ca unele activităţi să fie îndeplinite în regim de fond sau programul să continue să
reacţioneze la unele evenimente exterioare în timpul îndeplinirii unor calcule foarte
„costisitoare”. Pot fi aduse şi alte exemple.
70. Procese şi fire (3.6.1)
Numim proces în Windows o instanţă (un exemplar, o stare) a programului, încărcat în
memoria operativă. Această instanţă poate crea fire (thread) - secvenţe de instrucţiuni, care
urmează a fi executate. Este important să se înţeleagă că în Windows anume firele sunt
66
executate (nu procesele!), fiecărui proces fiindu-i asociat minimum un fir, numit firul principal al
aplicaţiei.
Deoarece în realitate există mult mai multe fire decât procesoare fizice, firele vor fi executate
secvenţial, timpul de procesor repartizându-se între fire. Dar viteza mare de execuţie şi frecvenţa
mare de comutare a firelor lasă impresia unei execuţii paralele a acestora.
Stările elementare ale unui fir sunt aceleaşi ca şi în cazul proceselor: ales (exe), eligibil
(ready) şi blocat (wait). Starea blocat este asociată aşteptării unui anume eveniment. Când
evenimentul se produce firul este trecut în mod automat în starea eligibil.
În cadrul sistemului de operare Windows există două tipuri de fire – fire interactive, care
execută un ciclu propriu de prelucrare a mesajelor (de exemplu, firul principal al unei aplicaţii) şi
fire de lucru, care sunt funcţii simple. În ultimul caz execuţia firului se încheie atunci când
calculele, generate de funcţia respectivă, iau sfârşit.
Merită atenţie şi modalitatea organizării ordinii de execuţie a firelor. Algoritmul FIFO este
departe de a fi cel mai optimal. În Windows toate firele sunt ordonate conform priorităţilor.
Prioritatea unui fir este un număr întreg de la 0 la 31 şi este determinată de prioritatea
procesului, care a generat firul şi prioritatea relativă a firului. În acest mod se ajunge la o
flexibilitate maximă, fiecărui fir punându-i-se la dispoziţie – în caz ideal – exact atâta timp de
procesor, cât are nevoie.
Prioritatea firului poate fi modificată dinamic. Firele interactive, care au prioritatea Normal,
sunt executate în mod deosebit de către sistem, prioritatea acestor fire fiind majorată, atunci când
procesul, care le-a generat, se află în planul central (foreground). În rezultat, aplicaţia curentă
reacţionează mai repede la cererile utilizatorului.
71. Necesitatea sincronizării (3.6.2)
Când un proces este creat în mod automat este creat firul principal al acestuia. Acest fir poate
crea în timpul execuţiei alte fire, care la fel pot crea fire noi şi aşa mai departe. Timpul de procesor
fiind repartizat între fire, fiecare fir „lucrează” în mod independent.
Toate firele unui proces împart resursele comune, de exemplu, spaţiul de adrese al memoriei
operative sau fişierele deschise. Aceste resurse aparţin întregului proces, deci şi fiecărui fir.
Fiecare fir poate să utilizeze aceste resurse fără nici un fel de restricţii. În realitate, din cauza
multitaskingului controlat (preemptive multitasking - la orice moment de timp sistemul poate
întrerupe execuţia unui fir şi transmite controlul unui alt fir), se poate întâmpla ca un fir să nu fi
terminat încă lucrul cu o resursă comună oarecare, iar sistemul să treacă la un alt fir, care
67
utilizează aceeaşi resursă. Rezultatele pot fi imprevizibile. Asemenea conflicte se pot produce şi în
cazul unor fire, care aparţin chiar unor procese diferite. Problema poate să apară întotdeauna când
două sau mai multe fire folosesc o resursă comună. De aceeea este necesar un mecanism de
coordonare a lucrului firelor cu resurse comune. În Windows acest mecanism se numeşte
sincronizarea firelor (thread synchronization).
72. Structura mecanismului de sincronizare în Windows (3.6.3)
Mecanismul de sincronizare este un set de obiecte ale sistemului de operare Windows, create
şi gestionate program, comune pentru toate firele sistemului şi utilizate pentru coordonarea
accesului la resurse. În calitate de resurse pot fi toate obiectele, care pot fi accesate de două şi mai
multe fire – un fişier pe disc, un port, un articol al unei baze de date, o variabilă globală a unui
program, accesibilă firelor unui singur procesor, un obiect al dispozitivului interfeţei grafice
(Graphic Device Interface), etc.
De obicei, sunt utilizate mecanismele (obiectele) de sincronizare, introduse mai sus:
excluderea mutuală (mutex), secţia critică (critical section), eveniment memorizat (event) şi
semaforul (semaphore), fiecare realizând metoda proprie de sincronizare. În calitate de obiecte
sincronizate pot fi chiar procesele sau firele (când un fir aşteaptă terminarea execuţiei unui proces
sau a unui alt fir), fişierele, dispozitivele de comunicaţie, etc.
Sensul mecanismelor de sincronizare constă în faptul, că fiecare poate să fie în starea set.
Atunci când un fir lucrează cu mecanismele de sincronizare (le creează, le modifică starea)
sistemul nu întrerupe execuţia firului, până nu va fi terminată această acţiune, adică toate operaţiile
finite din mecanismele de sincronizare sunt atomare (nu pot fi întrerupte).
Menţionăm de asemenea, că nu există nici o legătură reală între mecanismele de sincronizare
şi resurse. Mecanismele de sincronizare nu pot interzice accesul nedorit la o resursă, ele doar
indică firului momentul când acesta poate accesa resursa, sau când acesta trebuie să aştepte.
73. Administrarea obiectelor de sincronizare în Windows (3.6.4)
Crearea unui obiect de sincronizare se produce prin apelarea unei funcţii speciale din WinAPI
de tipul Create (ex.,CreateMutex). Acest apel returnează descriptorul obiectului (handle), care
poate fi folosit de toate firele procesului dat. Un obiect de sincronizare poate fi accesat şi dintr-un
alt proces, dacă acest proces a moştenit descriptorul obiectului dat, sau folosind funcţia de
deschidere a unui obiect (Open). Obiectului, dacă el nu este destinat doar pentru uz intern (în
68
interiorul unui singur proces), în mod obligator i se acordă un nume unic. Nu poate fi creat un
eveniment memorizat şi un semafor cu acelaşi nume.
Folosind descriptorul poate fi determinată starea curentă a obiectului cu ajutorul funcţiilor de
aşteptare. De exemplu, funcţia WaitForSingleObject(x, y) cu doi parametri (primul este
descriptorul obiectului, iar al doilea – timpul de aşteptare în ms) returnează WAIT_OBJECT_0,
dacă obiectul se află în starea set (adică nu aparţine nici unui fir şi poate fi utilizat pentru
sincronizare), WAIT_TIMEOUT – dacă a expirat timpul de aşteptare şi WAIT_ABANDONED,
dacă obiectul de sincronizare nu a fost eliberat înainte ca firul, care-l comanda, să se fi terminat.
Dacă timpul de aşteptare este egal cu 0, atunci funcţia returnează rezultatul imediat, în caz contrar,
aşteaptă intervalul de timp indicat. În cazul în care starea obiectului de sincronizare va deveni set
până la expirarea acestui timp, funcţia returnează WAIT_OBJECT_0, altfel - WAIT_TIMEOUT.
Dacă în parametrul timp este indicată constanta simbolică INFINITE, funcţia va aştepta până
când starea obiectului va deveni set, fără vre-o restricţie.
Starea mai multor obiecte poate fi aflată cu ajutorul funcţiei WaitForMultipleObjects. Pentru
încheierea lucrului cu un obiect de sincronizare şi eliberarea descriptorului se apelează funcţia
CloseHandle. Este important de ştiut, că apelarea unei funcţii de aşteptarea blochează firul curent,
adică atâta timp cât un fir se află în starea de aşteptare el nu are acces la procesor.
74. Excluderea mutual (3.6.4.1)
Cum a fost menţionat deja, mecanismele de excludere mutuală (mutex-ele, de la MUTual
EXclusion) permit coordonarea accesului la o resursă partajată (processor de ex.). Starea set a
obiectului corespunde momentului de timp în care obiectul nu aparţine nici unui fir şi poate fi
„utilizat”, iar starea reset – momentului când un fir oarecare controlează deja mutex-ul. Accesarea
va fi permisă doar după eliberare.
Pentru a lega mutex-ul de firul curent trebuie apelată una din funcţiile de aşteptare. Firul,
căruia îi aparţine mutex-ul, îl poate „ocupa” de mai multe ori, fără autoblocare, însă mai apoi
acesta va trebui eliberat tot de atâtea ori cu ajutorul funcţiei ReleaseMutex.
75. Evenimentele (3.6.4.2)
Obiectele-evenimente sunt utilizate pentru a informa firele, care sunt în aşteptare, despre
producerea unui eveniment. În Windows există două tipuri de evenimente – cu resetare manuală şi
automată. Resetarea manuală se execută cu funcţia ResetEvent. Aceste evenimente sunt folosite
69
pentru informarea mai multor fire, iar evenimentele cu resetare automată sunt utilizate pentru
informarea unui anumit fir, celelalte rămânând în aşteptare.
Funcţia CreateEvent crează un obiect-eveniment, funcţia SetEvent setează evenimentul în
starea set, iar funcţia ResetEvent resetează evenimentul. Funcţia PulseEvent setează evenimentul,
iar după semnalizarea firelor, care erau în aşteptare (toate în cazul resetării manuale şi doar unul la
resetarea automată), resetează obiectul. Dacă nu există fire în aşteptare, PulseEvent doar resetează
obiectul, fără semnalizare.
70
76. Semafoarele 71
77. Secţiunile critice 71
78 .Protejarea accesării variabilelor 71
79. Sincronizarea în MFC 71
80. Exemplu de sincronizare în Windows 72
81. Utilizarea secţiunilor critice în Windows 73
82. Structura RTL_CRITICAL_SECTION 75
83. Funcţii API pentru secţiunile critice 76
84. Clase de secţiuni critice 76
85. Depanarea secţiunilor critice 78
86. Administrarea proceselor. Realizarea excluderii mutuale. Specificarea problemei 78
87. Excluderea mutuală prin aşteptare activă 79
88. Algoritmul lui Dekker 79
89. Aşteptarea activă în sisteme multiprocesorale: Test & Set 80
90. Semaforul – instrument elementar pentru excluderea mutuală. Definiţii 81
91. Semaforul – Proprietăţi 82
92. Realizarea excluderii mutuale cu ajutorul semafoarelor 82
93. Funcţionarea şi structura unui nucleu de sincronizare. Stările unui proces. Fire de
aşteptare 84
94. Administrarea contextelor şi schemele primitivelor 86
95. Realizarea unui nucleu de sincronizare. Organizarea generală 88
96. Realizarea unui nucleu de sincronizare. Interfeţele 88
97. Realizarea unui nucleu de sincronizare. Structuri şi algoritmi 88
98. Realizarea unui nucleu de sincronizare. Realizarea monitoarelor. 90
99. Realizarea unui nucleu de sincronizare. Algoritmi de bază 90
100. Realizarea unui nucleu de sincronizare. Tratarea întreruperilor 92
71
76. Semafoarele
Un obiect-semafor este în ultimă instanţă un mutex cu contor. Acest obiect permite să
fie „ocupat” de un număr anume de fire, după care „ocuparea” va fi posibilă numai dacă unul
din fire va „elibera” semaforul. Semafoarele sunt utilizate pentru a limita numărul de fire,
care lucrează simultan cu resursa. La iniţializare se specifică numărul maxim de fire, la
fiecare „ocupare” valoarea contorului semaforului scade.
77. Secţiunile critice
Obiectul-secţiune critică permite programatorului să evidenţieze un fragment de cod în
care firul obţine acces la o resursă partajată, preîntâmpinând utilizarea resursei de mai mulţi
utilizatori. Pentru a utiliza resursa firul va intra mai întâi în secţiunea critică (apelarea
funcţiei EnterCriticalSection). Dacă intrarea a avut loc, nici un alt fir nu va avea acces la
aceeaşi secţiune critică, execuţia acestuia fiind suspendată. Reluarea se va produce în
momentul în care primul fir părăseşte secţiunea critică (funcţia LeaveCriticalSection).
Diferenţa de mutex constă în faptul că secţiunea critică este utilizată numai pentru firele unui
singur proces.
Cu ajutorul funcţiei TryEnterCriticalSection se poate stabili, dacă secţiunea critică este
liberă. Utilizând această funcţie, un proces, fiind în aşteptarea resursei, poate să nu se
blocheze, îndeplinind operaţii utile.
78. Protejarea accesării variabilelor
Există o serie de funcţii, care permit lucrul cu variabilele globale ale tuturor firelor, fără a
ne preocupa de sincronizare, deoarece aceste funcţii singure rezolvă problema sincronizării.
Aceste funcţii sunt InterlockedIncrement, InterlockedDecrement, InterlockedExchange,
InterlockedExchangeAdd şi InterlockedCompareExchange. De exemplu, funcţia
InterlockedIncrement incrementează valoarea unei variabile pe 32 biţi cu o unitate.
79. Sincronizarea în MFC(Microsoft Fundation Classes)
Biblioteca MFC conţine clase speciale pentru sincronizarea firelor (CMutex, CEvent,
CCriticalSection şi CSemaphore). Pentru utilizarea acestor clase trebuie consultaţi
constructorii şi metodele lor – Lock şi Unlock. În principiu, aceste clase sunt doar un fel de
ambalaj pentru obiectele de sincronizare.
O altă modalitate de utilizare a acestor clase constă în crearea aşa numitelor clase
thread-safe. O clasă thread-safe reprezintă o anumită resursă în program. Tot lucrul cu
resursa este realizat numai prin intermediul acestei clase, care conţine toate metodele
72
necesare. Clasa este proiectată în aşa mod, ca metodele ei să rezolve problema sincronizării,
adică în cadrul aplicaţiei să apară ca o simplă clasă. Obiectul de sincronizare MFC este inclus
în această clasă în calitate de membru privat şi toate funcţiile clasei, care realizează accesarea
resursei, îşi coordonează lucrul cu acest membru.
80. Exemplu de sincronizare în Windows
Prezentăm un exemplu simplu de lucru cu obiectul de sincronizare mutex [22].
#include <windows.h>
#include <iostream.h>
void main()
{
DWORD res;
// creăm obiectul excludere mutuală
HANDLE mutex = CreateMutex(NULL, FALSE, "NUME_APLICATIE-MUTEX01");
// dacă obiectul există deja, CreateMutex va returna descriptorul obiectul existent,
// iar GetLastError va returna ERROR_ALREADY_EXISTS
// timp de 20 s încercăm să ocupăm obiectul
cout<<"Încerc să ocup obiectul...\n"; cout.flush();
res = WaitForSingleObject(mutex,20000);
if (res == WAIT_OBJECT_0) // dacă ocupare s-a terminat cu succes
{
// aşteptăm 10 s
cout<<"L-am prins! Aşteptare 10 secunde...\n"; cout.flush();
Sleep(10000);
// eliberăm obiectul
cout<<"Acum eliberăm obiectul\n"; cout.flush();
73
ReleaseMutex(mutex);
}
// închidem descriptorul
CloseHandle(mutex);
}
Pentru a controla modul de funcţionare a mecanismului de excludere mutuală se vor lansa
două instanţe ale acestei aplicaţii. Prima instanţă va ocupa obiectul imediat şi-l va elibera doar
peste 10 secunde. Numai după aceasta instanţa a doua va reuşi să ocupe obiectul. În acest
exemplu obiectul de sincronizare este folosit pentru sincronizarea proceselor, din care cauză în
mod obligatoriu trebuie să aibă nume.
81. Utilizarea secţiunilor critice în Windows
Exemplu: fie variabila m_pObject şi câteva fire, care apelează metodele obiectului referit
de m_pObject. Presupunem că această variabilă din timp în timp îşi poate schimba valoarea,
valoarea 0 nu este interzisă. Fie următorul fragment de cod:
// Firul #1
void Proc1()
{
if (m_pObject)
m_pObject->SomeMethod();
}
// Firul #2
void Proc2(IObject *pNewObject)
{
if (m_pObject)
delete m_pObject;
m_pObject = pNewObject;
74
}
În acest exemplu există pericolul potenţial de apelare m_pObject->SomeMethod() după ce
obiectul a fost distrus cu ajutorul delete m_pObject, deoarece în sistemele de operare cu
multitasking controlat execuţia oricărui fir poate fi întreruptă în cel mai neconvenabil moment
şi să înceapă execuţia unui alt fir. Pentru exemplul nostru momentul nedorit este atunci când
firul #1 a testat deja m_pObject, dar nu a reuşit să apeleze SomeMethod(). Execuţia firului #1 a
fost întreruptă şi a început execuţia firului #2. Iar firul #2 reuşise deja să apeleze destructorul
obiectului. Ce se va întâmpla atunci când firului #1 i se va acorda din nou timp de procesor şi
va fi apelat SomeMethod() al unui obiect deja inexistent? Greu de presupus.
Aici ne vin în ajutor secţiunile critice. Să modificăm exemplul de mai sus.
// Firul #1
void Proc1()
{
::EnterCriticalSection(&m_lockObject);
if (m_pObject)
m_pObject->SomeMethod();
::LeaveCriticalSection(&m_lockObject);
}
// Firul #2
void Proc2(IObject *pNewObject)
{
::EnterCriticalSection(&m_lockObject);
if (m_pObject)
delete m_pObject;
m_pObject = pNewObject;
::LeaveCriticalSection(&m_lockObject);
}
75
Fragmentul de cod inclus între ::EnterCriticalSection() şi ::LeaveCriticalSection() cu una
şi aceeaşi secţiune critică în calitate de parametru nu va fi executat nici o dată în mod paralel.
Aceasta înseamnă, că dacă firul #1 a reuşit să „acapareze” secţiunea critică m_lockObject,
încercarea firului #2 să intre în aceeaşi secţiune critică va conduce la blocarea acestuia până în
momentul când firul #1 va elibera m_lockObject prin apelul ::LeaveCriticalSection(). Invers,
dacă firul #2 a accesat secţiunea critică înaintea firului #1, acesta din urmă va fi nevoit “să
aştepte”, înainte de a începe lucrul cu m_pObject.
Menţionăm, că secţiunile critice nu sunt obiecte ale nucleului sistemului de operare.
Practic, tot lucrul cu secţiunile critice are loc in procesul care le-a creat. Din aceasta rezultă, că
secţiunile critice pot fi utilizate numai pentru sincronizare în cadrul unui proces.
82. Structura RTL_CRITICAL_SECTION
Este definită după cum urmează:
typedef struct _RTL_CRITICAL_SECTION
{
PRTL_CRITICAL_SECTION_DEBUG DebugInfo; // Folosit de sistemul de operare
LONG LockCount; // Contorul de utilizări
LONG RecursionCount; // Contorul accesării repetate din firul utilizatorului
HANDLE OwningThread; // ID firului utilizatorului (unic)
HANDLE LockSemaphore; // Obiectul nucleului folosit pentru aşteptare
ULONG_PTR SpinCount; // Numărul de cicluri goale înaintea apelării nucleului
}
RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
Câmpul LockCount este incrementat cu o unitate la fiecare apelare ::EnterCriticalSection()
şi decrementat cu unu la fiecare apel ::LeaveCriticalSection().
În câmpul RecursionCount este păstrat numărul de apeluri repetate ::EnterCriticalSection()
din unul şi acelaşi fir.
Câmpul OwningThread conţine 0 în cazul secţiunilor critice libere sau identificatorul unic
al firului-posesor.
76
Câmpul LockSemaphore este folosit, dacă este necesar să se aştepte până secţiunea critică
este eliberată.
Dacă după un număr de SpinCount ori secţiunea critică nu a fost eliberată, trecem în starea
blocat.
83. Funcţii API pentru secţiunile critice
Funcţiile BOOL InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) şi
BOOL InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection,
DWORD dwSpinCount). După apelare secţiunea critică este gata de lucru.
Funcţia DWORD SetCriticalSectionSpinCount(LPCRITICAL_SECTION
lpCriticalSection, DWORD dwSpinCount) setează valoarea câmpului SpinCount şi returnează
valoarea precedentă a acestuia.
VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) eliberează
resursele, ocupate de secţiunea critică.
VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection), BOOL
TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) permit intrarea în
secţiunea critică. Dacă secţiunea critică este ocupată de un alt fir, atunci ::EnterCriticalSection()
va aştepta până aceasta va fi eliberată, iar ::TryEnterCriticalSection() va returna valoarea
FALSE.
VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) eliberează
secţiunea critică.
84. Clase de secţiuni critice
Pentru o utilizare corectă a secţiunilor critice voi prezenta mai jos codul claselor
secţiunilor critice:
class CLock
{
77
friend class CScopeLock;
CRITICAL_SECTION m_CS;
public:
void Init() { ::InitializeCriticalSection(&m_CS); }
void Term() { ::DeleteCriticalSection(&m_CS); }
void Lock() { ::EnterCriticalSection(&m_CS); }
BOOL TryLock() { return ::TryEnterCriticalSection(&m_CS); }
void Unlock() { ::LeaveCriticalSection(&m_CS); }
};
class CAutoLock : public CLock
{
public:
CAutoLock() { Init(); }
~CAutoLock() { Term(); }
};
class CScopeLock
{
LPCRITICAL_SECTION m_pCS;
public:
CScopeLock(LPCRITICAL_SECTION pCS) : m_pCS(pCS) { Lock(); }
CScopeLock(CLock& lock) : m_pCS(&lock.m_CS) { Lock(); }
~CScopeLock() { Unlock(); }
void Lock() { ::EnterCriticalSection(m_pCS); }
void Unlock() { ::LeaveCriticalSection(m_pCS); }
78
};
Clasele CLock şi CAutoLock sunt utilizate, de obicei, pentru sincronizarea accesării
variabilelor clasei, iar CScopeLock este destinat, în special, pentru a fi utilizată în proceduri.
85. Depanarea secţiunilor critice
Depanarea secţiunilor critice este o ocupaţie foarte interesantă, dar şi dificilă. Poţi căuta
ore şi chiar zile în şir cauza apariţiei unei probleme. Erorile, legate de secţiunile critice sunt de
două tipuri: de realizare şi de arhitectură.
Erorile de realizare pot fi depistate relativ uşor şi, de regulă, sunt generate de utilizarea
incorectă (lipsa perechii) a apelurilor ::EnterCriticalSection() şi ::LeaveCriticalSection().
Dintre erorile de arhitectură cea mai frecventă este îmbrăţişarea fatală (deadlock,
v.5.1.3.3), când două fire încearcă să acceseze două şi mai multe secţiuni critice.
Retine studentule:
Secţiunile critice sunt executate relativ repede şi nu cer multe resurse de sistem;
Pentru sincronizarea accesării a mai multor variabile independente este mai bine să fie
utilizate câteva secţiuni critice (nu una pentru toate variabilele);
Codul unei secţiuni critice va fi redus la minimum;
Nu este recomandat să fie apelate metode ale unor obiecte “străine” dintr-o secţiune
critică.
86. Administrarea proceselor. Realizarea excluderii mutuale. Specificarea problemei
Mecanismele care realizează excluderea mutuală pentru un set de programe sunt bazate pe
un principiu comun: utilizarea mecanismului de excludere mutuală existent deja la un nivel
inferior. La nivelul de există două mecanisme elementare: excluderea mutuală la accesarea
unui amplasament de memorie şi masca întreruperilor. Aceste două mecanisme sunt, în
principiu, suficiente pentru toate necesităţile. Dar, din considerente de eficacitate, la nivelul
resurselor fizice sau microprogramelor există dispozitive mai sofisticate, cum ar fi instrucţiunea
Test and Set sau semafoarele.
79
Voi preciza mai întâi problema excluderii mutuale. Fie {p1, p2,...,pn} o mulţime de
procese pe care le vom considera ciclice; programul fiecărui proces conţine o secţiune critică.
Excluderea mutuală este asigurată prin două fragmente de program: prolog şi epilog.
Presupunem, că fiecare proces, care intră în secţiunea critică o părăseşte într-un interval de timp
finit.
Soluţia trebuie să posede următoarele proprietăţi:
a) excludere mutuală: la fiecare moment de timp cel mult un proces execută secţiunea
critică,
b) absenţa blocajelor intempestive: dacă în secţiunea critică nu se află vreun
proces, nici un proces nu trebuie să fie blocat de mecanismul excluderii mutuale,
c) toleranţă la defecte: soluţia trebuie să rămână validă şi în cazul unor defecte în
unul sau în mai multe procese, care se află în afara secţiunii critice,
d) absenţa privaţiunilor: un proces, care a cerut intrarea într-o secţiune critică
nu trebuie să aştepte un timp infinit
e) simetrie: prologul şi epilogul trebuie să fie identice pentru toate procesele şi
independente de numărul lor.
Ţinând cont de aceste specificaţii vom construi o soluţie de forma:
<iniţializare> -- comună tuturor proceselor
<programul procesului pi>:
ciclu
<prolog> -- intrare în secţiunea critică
<secţiunea critică>
<epilog> -- ieşire din secţiunea critică
<restul programului>
endciclu
87. Excluderea mutuală prin aşteptare activă
Un proces în aşteptare activă simulează blocarea efectuând o testare repetată a condiţiei
de depăşire, care poate fi actualizată de alte procese. (In calitate de exemplu este Algoritmul lui
Dekker)
88. Algoritmul lui Dekker
Algoritmul lui Dekker ne ajuta sa construim o solutie fără a folosi alte mecanisme de
excludere mutuală, în afară de indivizibilitatea accesării în citire sau actualizarea unui
80
amplasament de memorie. Prezint algoritmul pentru două procese, deşi el poate fi extins pentru
un număr arbitrar de procese.
Programul foloseşte trei variabile comune celor două procese:
var c : array [0..1] of boolean;
tur : 0..1;
iniţializare: c[0]:=c[1]:=false;
tur:=0;
prolog : -- pentru procesul i; se va pune j=1-i (celălalt proces)
c[i]:=true;
tur:=j;
test: if c[j] and tur=j then
go to test
endif;
...
epilog : -- pentru procesul i
c[i]:=false;
Aici condiţia de aşteptare e reprezentata printr-o variabilă booleană c , adica c = “un
proces este în secţiunea critică”
Aşteptarea activă poate fi în egală măsură utilizată ca mecanism elementar de sincronizare
în cazul unor alte probleme, diferite de excluderea mutuală.
89. Aşteptarea activă în sisteme multiprocesorale: Test & Set
Instrucţiunea Test And Set (tas), este utilizată în sistemele multiprocesorale, pentru tratarea
cu ajutorul aşteptării active a cazului în care mai multe procese actualizează şi consultă
variabile commune.
Fie m adresa amplasamentului de memorie considerat, sau lacătul, iar R un registru al
procesorului. Prin convenţie, dacă lacătul este în 0, secţiunea critică este liberă, iar dacă este 1 –
ea este ocupată:
tas R, m : <blocare acces la Mp[m]>
81
R:=Mp[m]
Mp[m]:=1
<eliberare acces la Mp[m]>
Excluderea mutuală prin aşteptare activă poate fi programată cu ajutorul următoarelor
secvenţe:
iniţializare: stz m -- Mp[m]:=0
prolog : tas R, m
br(R≠0) $-1 -- test iterat
epilog : stz m
90. Semaforul – instrument elementar pentru excluderea mutuală. Definiţii
Un semafor s este constituit prin asocierea unui contor cu valori întregi, notat s.c., şi a
unui fir de aşteptare, notat s.f. si serveşte la blocarea proceselor aşteptând să se producă o
condiţie pentru deblocarea lor; procesele blocate sunt plasate în s.f.
Un procesor poate fi manipulat doar cu ajutorul a două operaţii P(s) şi V(s), numite
primitive.
Fie p un proces care execută P(s) sau V(s), iar q un proces care se află în firul de aşteptare
s.f. Algoritmul primitivelor este următorul:
P(s): V(s):
s.c.:=s.c.-1; s.c.:=s.c.+1;
if s.c.<0 then if s.c.≤0 then
stare(p):=blocat; extragere(q,s.f.);
introducere(p,s.f.) stare(q):=activ
endif endif
Operaţiile introducere şi extragere permit inserarea unui proces într-un fir de aşteptare
sau, respectiv, extragerea.
Doar executarea primitivei P poate bloca un proces, acesta va putea fi deblocat doar de un
alt proces, care a executat primitiva V pe acelaşi semafor.
82
91. Semaforul – Proprietăţi
Proprietăţile principale ale sincronizării cu ajutorul semafoarelor pot fi deduse din câteva
relaţii invariante: relaţii verificate iniţial şi relatii care rămân neschimbate după executarea
primitivelor P şi V un număr arbitrar de ori.
1) Fie, pentru un semafor s:
np(s) – numărul total de execuţii a operaţiei P(s),
nv(s) – numărul total de execuţii a operaţiei V(s).
Are loc relaţia: s.c. = s0 – np(s) + nv(s) (1)
deoarece valoarea iniţială a lui s.c. este s0, fiecare operaţie P(s) scade din această valoare o
unitate, iar V(s) adaugă 1.
2) Fie nbloc(s) numărul proceselor blocate în s.f. Are loc relaţia:
nbloc(s) = if s.c. ≥ 0 then 0 else –s.c. endif
(2)
care poate fi de asemenea scrisă
nbloc(s) = max(0, –s.c.) (21)
3) Relaţia (2) poate fi scrisă sub o altă formă. Fie nf(s) numărul de “treceri” de către
procese a primitivei P(s), adică suma numărului de executări a lui P(s) fără blocare şi a
numărului de deblocări realizate de către V(s). Vom avea în acest caz:
nbloc(s) = np(s) – nf(s).
Introducând această valoare în (21) obţinem:
- nf(s) = max(-np(s), -s.c.-np(s)), sau
nf(s) = min(np(s), s.c.+np(s)).
În fine, utilizând valoarea lui s.c. din (1), avem:
nf(s) = min(np(s), s.c.+nv(s)). (3)
92. Realizarea excluderii mutuale cu ajutorul semafoarelor
Prezint o schemă, care rezolvă problema excluderii mutuale pentru n procese.
iniţializare : semafor mutex init 1
83
prolog : P(mutex),
epilog : V(mutex).
Fie nc numărul de procese, care se află în secţiunea critică la un moment concret de timp.
Avem:
nc = nf(mutex) – nv(mutex) (4)
Proprietăţile în cauză pot fi verificate aplicând semaforului mutex relaţia (3) :
nf(mutex) = min(np(mutex), 1+nv(mutex)) (5)
a) Excluderea mutuală
Din (5) avem:
nf(mutex) ≤ 1+nv(mutex)
şi, utilizând (4), obţinem nc ≤ 1: excluderea mutuală este asigurată.
b) Absenţa blocajelor
Presupunem, că nici un proces nu se află în secţiunea critică. Vom avea în acest caz nc = 0,
sau
nf(mutex) = nv(mutex) sau încă
nf(mutex) ≤ 1+nv(mutex)
Vom avea conform relaţiei (5):
nf(mutex) = np(mutex) sau
nbloc(mutex) = 0
1). Secţiuni critice incorporate. Blocaje
Voi considera două procese p şi q pentru care programul conţine două secţiuni critice
distincte, corespunzătoare utilizării a două resurse critice distincte.
procesul p procesul q
... ...
(1) P(mutex1) (11) P(mutex2)
... ...
(2) P(mutex2) (21) P(mutex1)
... ...
84
V(mutex2) V(mutex1)
... ...
V(mutex1) V(mutex2)
Dacă traiectoria temporală de execuţie a proceselor p şi q începe cu (1, 11, 2, 2
1), se va
ajunge la o situaţie în care ambele procese sunt blocate pentru un timp infinit, deoarece fiecare
dintre procese poate fi deblocat doar de către celălalt. Această situaţie este numită
2). Aşteptare infinită în secţiunea critică sau impas
Validitatea soluţiei propuse se bazează pe presupunerea, că toate procesele părăsesc
secţiunea critică în timp finit. Dar pot fi şi cauze, care conduc la o aşteptare infinită. Astfel,
blocarea, incorectitudini sau ciclări infinite într-un proces, care se află în secţiunea critică, pot
paraliza toate procesele concurente cu procesul dat. În cazul unor secţiuni critice globale (care
prezintă interes pentru toţi utilizatorii), realizate pentru un sistem de operare, pot fi propuse
următoarele soluţii:
oricărui proces, care execută o secţiune critică globală, i se atribuie, pe toată durata
acestei execuţii, un statut special, care îi conferă anumite drepturi particulare: prioritate
înaltă, protecţie contra distrugerii, etc.
un orologiu de gardă este armat la intrarea unui proces în secţiunea critică; dacă
procesul nu părăseşte secţiunea critică după un interval de timp predefinit, sistemul de
operare forţează ieşirea procesului şi eliberează astfel secţiunea critică. Această soluţie nu
este cea mai bună, or datele globale, manipulate în secţiunea critică, pot să devină
incoerente. Este necesar să se ofere posibilitatea restabilirii acestor date la o stare
anterioară, considerată validă, ceea ce implică salvări periodice.
3). Privaţiune
Algoritmul excluderii mutuale garantează intrarea exact a unui proces în secţiunea critică,
dacă mai multe procese încearcă acest lucru, când secţiunea critică este liberă. Se poate
întâmpla ca un proces particular să fie reţinut pentru un interval de timp nedefinit: acest
fenomen se numeşte privaţiune.
93. Funcţionarea şi structura unui nucleu de sincronizare. Stările unui proces. Fire
de aşteptare
85
Noţiunea de proces şi operaţiile asociate sunt implementate cu ajutorul unor programe
şi/sau microprograme, care formează nucleul de administrare a proceselor. În cadrul descrierii
unui sistem de operare cu ajutorul maşinilor abstracte ierarhice , nucleul constituie nivelul cel
mai inferior, realizat direct pe maşina fizică. Maşina abstractă, realizată astfel poate fi numită o
maşină a proceselor, care posedă, în afara setului de instrucţiuni de bază, primitivele care
permit crearea, distrugerea şi sincronizarea proceselor. Ca şi orice maşină abstractă, maşina
realizată în acest mod ascunde unele proprietăţi ale maşinii fizice. Astfel:
noţiunea de proces, care este echivalentă cu cea de proces virtual, ascunde
utilizatorilor nucleului mecanismul de alocare a procesoarelor fizice. La un nivel superior
nivelului nucleului chiar şi numărul procesoarelor nu intervine decât doar asupra
performanţelor sistemului şi nici într-un fel asupra structurii sale logice,
primitivele de sincronizare, realizate de nucleu, ascund mecanismele fizice de
comutare a contextului, de exemplu, cele oferite de întreruperi.
Structura unui nucleu de sincronizare depinde, printre altele, de specificaţiile maşinii fizice
(gestiunea întreruperilor, structura cuvântului de stare, sistem mono- sau multiprocesoral, etc.)
şi de specificaţiile maşinii abstracte care trebuie realizate, îndeosebi de mecanismul de
sincronizare ales.
Stările unui proces
Am considerat până acuma că un proces se poate afla în două stări: activ sau blocat.
Luarea în consideraţie a alocării fizice a unui procesor ne impune să descompunem starea
activă în două stări noi. Un proces activ se numeşte ales, dacă el este în curs de execuţie pe un
procesor fizic; el se numeşte eligibil dacă nu poate fi executat din cauza lipsei unui procesor
disponibil. Figura 4.1 descrie stările unui proces şi tranziţiile lui.
Tranziţiile 3 şi 4 (blocare şi deblocare) sunt tranziţiile “interne”, datorate sincronizării
proceselor. Tranziţiile “tehnologice” 1 şi 2 sunt datorate alocării procesoarelor fizice
proceselor.
eligibil
(ready
ales
(exe)
blocat
(wait)
(1)
(2)
(3) (4)
Fig.4.1. Stările unui proces
86
Fire de aşteptare
Administrarea proceselor face apel la fire de aşteptare. Astfel, fiecărei cauze distincte de
blocare (semafor, condiţie într-un monitor, etc.) i se asociază un fir de aşteptare pentru a stabili
o ordine a proceselor blocate.
Mulţimea programelor, care realizează aceşti algoritmi se numeşte planificator .
Programul, care realizează alegerea propriu-zisă se numeşte dispecer. Schema generală a
firelor de aşteptare ale proceselor este prezentată în fig.4.2. Deplasarea proceselor între aceste
fire corespunde schimbării stării.
94. Administrarea contextelor şi schemele primitivelor
1) Conţinutul contextului
Operaţia de alocare a procesorului fizic impune păstrarea pentru fiecare proces a unei copii
a contextului. Această copie a contextului descrie starea procesorului pentru procesul
considerat. În acest scop fiecărui proces i se asociază o mulţime de informaţii rezidente în
firul proceselor eligibile
fire de procese
blocate
planificator
dispecer proces ales
Fig.4.2. Fire de aşteptare ale proceselor, administrate de nucleul sistemului de operare
87
memorie şi numită vector de stare, bloc de control al procesului sau blocul contextului, care
conţine:
informaţiile despre starea procesorului, necesare la realocarea lui (conţinutul
cuvântului de stare, registrelor),
valorile atributelor procesului (prioritate, drept de acces),
pointeri la spaţiul de lucru al procesului (segmentele procedură şi date, stiva de
execuţie),
informaţii de gestiune (starea, legăturile de înlănţuire).
2) Organizarea nucleului
Execuţia programelor nucleului este declanşată în două moduri (fig.4.3):
prin apelarea unei primitive de administrare a proceselor (creare, distrugere,
sincronizare, etc.); aceste primitive sunt realizate sub formă de apel al supervizorului,
printr-o întrerupere: programele de tratare a întreruperilor fac parte din nucleu,
deoarece întreruperile sunt traduse în operaţii de sincronizare şi sunt invizibile la
nivelurile superioare.
Programul unei primitive a nucleului are următoarea schemă generală:
prolog; -- salvarea contextului şi intrarea în secţiunea critică
control; -- verificarea drepturilor şi a parametrilor
<corpul programului> -- manipulează firele proceselor
alocare_procesor; -- programul dispecer şi ieşirea din secţiunea critică
Tratarea întreruperilor de către nucleu trebuie să fie coordonată cu mecanismele de
sincronizare alese. De obicei sunt considerate două scheme de bază:
1) Asocierea unui proces, care tratează fiecare întrerupere.
Doar acest proces se va afla în aşteptarea unei întreruperi anume, existând pentru aceasta
o instrucţiune specială.
întreruperi
alocare procesor apelare supervizor
lansare
periferice,
ceasul
programul
nucleului
proces
Fig.4.3. Comunicarea cu un nucleu de sincronizare
88
2) Asocierea unei operaţii de deblocare la o întrerupere.
95. Realizarea unui nucleu de sincronizare. Organizarea general
96. Realizarea unui nucleu de sincronizare. Interfeţele
a) Gestionarea proceselor
Procesele pot fi create şi distruse în mod dinamic, şi sunt organizate ierarhic conform
relaţiei de legătură (v.3.5). Un proces este creat cu ajutorul primitivei:
creare(p, context iniţial, atribute)
Atributele unui proces conţin prioritatea şi drepturile de a executa anumite operaţii.
Contextul iniţial specifică starea iniţială a cuvântului de stare şi a registrelor procesorului, şi a
spaţiului de lucru asociat procesului. Procesul este creat în starea eligibil. Numărul său p
(numele) este returnat ca rezultat (valoarea nil, dacă crearea este imposibilă). O funcţie
determină_număr_propriu permite unui proces să afle numărul său propriu.
Primitivele care urmează pot fi aplicate unui proces existent şi pot fi executate doar de
procesul-părinte.
Procedura distrugere poate fi utilizată de către un proces pentru a se autodistruge. Deci,
distrugere(p) va distruge toate procesele desemnate de procesul p şi toţi descendenţii acestora.
Procedura suspendare(p) întrerupe execuţia unui proces p, plasându-l într-un fir de
aşteptare special. Execuţia lui p poate fi reluată doar cu ajutorul primitivei reluare(p).
Primitivele suspendare şi reluare sunt introduse din considerente de securitate, în special pentru
a permite monitorizarea unui proces de către procesul-părinte.
Utilizarea primitivelor creare, distrugere, suspendare şi reluare este condiţionată de un
drept, care figurează în atributul drepturi al procesului.
b) Sincronizarea
Procesele sunt sincronizate cu ajutorul monitoarelor. Gestiunea întreruperilor este integrată
în mecanismul monitoarelor: o întrerupere este asociată unei condiţii.
97. Realizarea unui nucleu de sincronizare. Structuri şi algoritmi
Din momentul creării sale unui proces i se asociază un număr fix (process handler), care
serveşte la desemnarea lui şi permite accesarea blocului său de context. Blocul de context
conţine următoarele câmpuri:
89
Csp : zona de salvare a cuvântului de stare a procesorului,
Reg : zona de salvare a registrelor generale ale procesorului,
Stare : valoarea stării procesului (eligibil, blocat, ...),
Prio : prioritatea procesului,
Drepturi : drepturile procesului,
Fire, etc. : legături de înlănţuire în ierarhia proceselor,
Suc, etc. : legături de înlănţuire în firele de aşteptare (FA).
Administrarea proceselor utilizează fire de aşteptare, ordonate în ordinea de descreştere a
priorităţilor şi comandate de un set de proceduri de accesare, specificate mai jos (p specifică un
proces, f – un fir de aşteptare):
introducere(p, f) Introduce p în f, în elementul lui f care corespunde
priorităţii procesului şi în ordinea sosirii pentru procesele cu aceeaşi prioritate.
primul(f) Întoarce numărul (numele) procesului din vârful lui f (nil dacă f este
vid); nu modifică f.
ieşire(p, f) Extrage din firul f primul proces, numărul acestuia fiind pus în p (nil
dacă f este vid).
extragere(p, f) Extrage din firul f procesul cu numărul p
specificat, oricare ar fi elementul în care acesta se află; pune în p valoare nil,
dacă procesul nu există în firul f.
vid(f) Funcţie booleană cu valoarea adevărat, dacă firul f este vid, fals în caz contrar.
90
98. Realizarea unui nucleu de sincronizare. Realizarea monitoarelor
1) Semantica primitivei semnalizare. Specificarea iniţială a primitivei c.semnalizare
precizează că unul din procesele care sunt în aşteptarea condiţiei c (dacă există) este imediat
deblocat, ceea ce implică trecerea temporară în starea blocat a procesului care execută
semnalizare. În specificarea prezentă procesul deblocat este simplu trecut în starea eligibil şi
trebuie să intre în monitor; el se află, deci, în competiţie cu alte procese, care aşteaptă să intre în
monitor, şi nu este garantat că va fi imediat ales. Condiţia, care provocase deblocarea, poate fi
modificată înainte ca procesul deblocat să-şi reia execuţia în monitor. Pentru această nouă
interpretare trebuie să fie modificată forma punerii în aşteptare. O construcţie de forma
if continuare_non_posibilă then
c.aşteptare
endif
devine în acest caz
while continuare_non_posibilă do
c.aşteptare
endwhile
2) Deblocare multiplă. Problema deblocării multiple poate fi rezolvată uşor
introducând o primitivă nouă c.difuzare_semnal efectul căreia se exprimă astfel:
while c.non_vid do
c.semnalizare
endwhile
Fiind dat, că toate procesele deblocate vor testa din nou condiţia şi cer din nou acces la
monitor, această primitivă va avea evident efectul aşteptat.
3) Întârziere de gardă. Din probleme de securitate, în special pentru tratarea
blocajelor, poate fi util să se asocieze o întârziere de gardă condiţiei unui monitor. Această
întârziere este egală cu durata maximă de blocare a unui proces într-un fir de aşteptare asociat
condiţiei date. La expirarea întârzierii de gardă va fi efectuată o tratare specificată. Această
tratare poate consta în simpla deblocare a procesului (care va testa din nou condiţia de depăşire)
sau transferul său într-un fir de aşteptare special (v.4.3.2.3).
91
Fie M.c.întârziere întârzierea de gardă asociată unei condiţii c în monitorul M. Se
presupune disponibil un ceas habs, care pune la dispoziţie timpul absolut. Trebuie să adăugăm în
programul primitivei c.semnalizare instrucţiunea următoare:
hdeblocare[p]:=habs+M.c.întârziere
unde hdeblocare[p] este un câmp nou al blocului de context al procesului p. Un proces, numit
“gardian”, deblocat la intervale regulate de timp parcurge mulţimea contextelor şi efectuează
tratamentul specificat proceselor pentru care hdeblocare[p]>habs.
99. Realizarea unui nucleu de sincronizare. Algoritmi de bază
Programul monitorului trebuie să asigure două funcţii:
excluderea mutuală pentru procedurile monitorului,
blocarea şi deblocarea asociate primitivelor aşteptare şi semnalizare.
Fiecărui monitor M îi sunt asociate următoarele structuri de date:
un dispozitiv de excludere mutuală M.disp (lacăt), care poate lua două valori liber
şi ocupat, şi un fir de aşteptare M.fir asociat acestui dispozitiv. Iniţial M.disp=liber,
M.fir=<vid>.
fiecărei condiţii c de M îi este asociat un fir M.c.fir, un contor de gardă
M.c.întârziere şi, pentru condiţiile asociate unei întreruperi, un indicator boolean
M.c.într_sosită.
Firul proceselor eligibile este determinat de f_eligibil.
Pentru un monitor M vom cerceta programul a patru secvenţe intrare, ieşire, c.aşteptare şi
c.semnalizare (secvenţele intrare şi ieşire sunt inserate de compilator şi încadrează execuţia
procedurilor externe ale monitorului). Să definim mai întâi procedurile de gestiune a
dispozitivului:
cerere_disp(M, p): eliberare_disp(M):
if M.disp=ocupat then if vid(M.fir) then
intrare(p, M.fir); M.disp:=liber
stare[p]:=blocat else
else ieşire(q, M.fir);
M.disp := ocupat; intrare(q, f_eligibil);
intrare(p, f_eligibil); stare[q]:=eligibil
stare[p]:=eligibil endif
92
endif
Cele patru secvenţe se vor scrie utilizând următoarele proceduri:
intrare(M): ieşire(M):
prolog; prolog;
p:=<proces apelant>; p:=<proces apelant>;
cerere_disp(M, p); eliberare_disp(M);
alocare_procesor; intrare(p, f_eligibil);
alocare_procesor;
c.aşteptare: c.semnalizare:
prolog; prolog;
p:=<proces apelant>; p:=<proces apelant>;
intrare(p, M.c.fir); if non_vid(M.c.fir) then
stare[p]:=blocat; ieşire(q, M.c.fir);
eliberare_disp(M); cerere_disp(M, p);
alocare_procesor; cerere_disp(M, q);
eliberare_disp(M)
else
intrare(p, f_eligibil)
endif
alocare_procesor;
100. Realizarea unui nucleu de sincronizare. Tratarea întreruperilor
Pentru asigurarea uniformităţii mecanismelor de sincronizare fiecărei întreruperi i se
asociază:
o condiţie într-un monitor,
un proces ciclic care realizează tratarea întreruperilor, în stare de repaus acest
proces este în aşteptarea condiţiei.
O condiţie poate fi asociată unui singur nivel de întrerupere. Sosirea unei întreruperi
provoacă executarea funcţiei semnalizare pentru condiţia asociată. Prioritatea relativă a
întreruperilor este tradusă în prioritatea proceselor, care tratează întreruperile.
93
Mecanismul descris mai sus nu este absolut perfect. De exemplu, excluderea procedurilor
monitorului nu poate fi aplicată întreruperilor. Se poate întâmpla ca o întrerupere să fie cerută
atunci când procesul, care tratează întreruperile, este încă activ, din care cauză întreruperea va fi
pierdută. Evitarea acestui fenomen se va face cu ajutorul unui indicator boolean, care
memorizează sosirea unei întreruperi. Vom avea:
<proces de prelucrare a întreruperii>
ciclu
test if nonM.c.într_sosită then
c.aşteptare; -- evitarea pierderii unei întreruperi
go to test
endif;
<tratarea întreruperii>
endciclu
<sosirea unei întreruperi asociate lui M.c>
M.c.într_sosită := true;
c.semnalizare;