Documente Academic
Documente Profesional
Documente Cultură
4-1
c) Afişarea automată a informaţiei de stare.
S.O. sunt dinamice, în sensul că, în permanenţă pot fi adăugate noi funcţii sau rescrise
programele ce realizează funcţii deja implementate.
4.1.3. Funcţia de gestiune. Principala sarcină a unui S.O. este aceea de gestiune a
resurselor sistemului de calcul: unitatea centrală, memoria principală (internă), perifericele de I/E,
bibliotecile şi fişierele de date. Programele pentru gestiune ale unui S.O. pot fi împărţite în 4 mari
categorii:
1) Funcţia de gestiune a memoriei, cu următoarele atribute:
- ţine evidenţa utilizării memoriei, adică permite cunoaşterea în orice moment a zonelor
de memorie libere şi ocupate;
- decide ce proces primeşte memorie, când şi ce cantitate de memorie i se alocă. Alocarea
memoriei se face atât pentru păstrarea programului corespunzător procesului cât şi pentru
necesităţile de execuţie.
- asigură tehnici corespunzătoare de protecţie a memoriei;
- dezalocă resursa când procesul s-a încheiat sau nu mai are nevoie de o anumită cantitate
de memorie.
2) Funcţia de gestiune a procesorului şi proceselor:
- ţine evidenţa procesorului precum şi evidenţa stării proceselor;
- decide prioritatea în utilizarea procesorului, în funcţie de prioritatea lucrărilor ce trebuie
executate;
- planificatorul lucrărilor alocă resursele procesorului necesare realizării unui proces
(lucrare);
- eliberează resursa când procesul nu mai are nevoie de procesor sau când s-a depăşit o
anumită cuantă de timp alocată pentru utilizare.
3) Funcţia de gestiune a dispozitivelor periferice are rolul de a aloca resursele şi a
iniţializa operaţiile de I/E precum şi de a dezaloca aceste resurse când operaţiile de I/E s-au
încheiat.
4) Funcţia de gestiune a informaţiei:
- ţine evidenţa resurselor (fişierelor) şi localizarea acestora pe suporturi magnetice;
- oferă rutinele de acces la informaţie;
- alocă şi dezalocă informaţie prin funcţia de deschidere şi respectiv de închidere a
fişierelor.
Deci, putem spune că:
- funcţia de gestiune trebuie să prevadă funcţiile de control automat prin rutine
specializate asupra tuturor resurselor fizice şi logice ce apar;
- să asigure o cât mai mare independenţă a programelor utilizator faţă de particularităţile
sistemului pe care s-a implementat S.O.;
- să rezolve toate problemele de control al funcţionării sistemului printr-un procedeu
performant de tratare a întreruperilor (utilizarea întreruperilor permite un dialog foarte flexibil
între U.C. şi mediul extern, permiţând semnalarea promptă a diverselor evenimente interne sau
externe);
- să permită modificarea configuraţiei de echipamente periferice, fără ca aceasta să
afecteze programele deja implementate.
Din punct de vedere al utilizatorului, S.O. apare ca o interfaţă între programele sale de
aplicaţii şi echipamentele (elementele) sistemului de calcul, care poate fi reprezentată printr-o
structură ierarhică de forma din Fig. 4.1.
4-2
Se observă că accesul direct la resursele sistemului de calcul este puternic limitat de
existenţa a două nivele intermediare: procesorul de limbaj şi S.O. Fiecare nivel introduce funcţii
noi inexistente la nivelele inferioare definind o maşină virtuală corespunzătoare acelui nivel.
Fig. 4.1.
S.O. pot fi scrise într-un limbaj de nivel evoluat numai la nivelele superioare, care nu
interacţionează direct cu maşina fizică.
Existenţa nucleului este obligatorie în orice S.O. Nucleul conţine funcţiile privind tratarea
operaţiilor de I/E la nivel fizic, tratarea întreruperilor, tratarea sincronizării şi comunicării între
procese, care sunt scrise, de obicei, în cod maşină sau limbaj de asamblare. Funcţiile care
formează nucleul S.O. sunt intens utilizate de celelalte două nivele superioare şi, din această
cauză, se implementează prin secvenţe de program rezidente în M.O. într-o zonă special rezervată
acestui scop.
Funcţiile de suport pentru execuţia programului sunt apelate în timpul execuţiei unui
program printr-un procedeu asemănător apelului macroinstrucţiunilor, adică prin folosirea unor
parametri. Nu toate funcţiile acestui nivel sunt rezidente în memorie, ci numai acele funcţii care
sunt cel mai des utilizate, iar celelalte se încarcă numai în funcţie de necesităţi.
Nivelul superior (3) constă din programe relativ rar apelate, care permit aducerea unui
program în starea în care să poată fi executat. Programele scrise în limbaje evoluate utilizează
S.O. tocmai la acest nivel.
Orice acces al programelor utilizator la funcţiile de la nivelele 2 şi 1 se realizează indirect
(şi din această cauză, acest nivel se numeşte suport de pregătire a programelor). Apelul la
componentele S.O. se realizează printr-un limbaj de comandă specific S.O. respectiv.
Într-o succesiune normală, un program de aplicaţie parcurge, înainte de a fi executat,
următoarele etape: introducerea în sistem, compilarea, editarea de legături, activarea programului.
4-3
Nu este obligatoriu ca toate lucrările să parcurgă toate aceste etape. Sunt lucrări la care fiecare
fază poate să apară o dată sau de mai multe ori.
Fiecăreia din etapele prezentate, în S.O. îi corespund programe specifice: compilatoare,
editoare de legături, editoare de rapoarte pentru prezentarea rezultatelor etc.
4-4
Vizibilitatea indică măsura în care un utilizator poate avea acces la programele ce implementează
anumite funcţii ale S.O. Există situaţii în care, deşi nu este absolut necesar, utilizatorul are nevoie
să cunoască anumite informaţii specifice activităţii S.O. pentru a putea creşte eficienţa
programelor sale de aplicaţie.
4-5
Menţionăm însă că nici multiprogramarea şi nici multitaskingul nu impun capacitatea de
prelucrare multiplă din partea sistemului de calcul, deci astfel de S.O. pot fi implementate şi pe
sisteme monoprocesor.
Sistemele de calcul destinate conducerii proceselor industriale trebuie să posede în mod
necesar sisteme de operare în timp real cu facilităţi multitasking. O particularitate esenţială a unui
astfel de S.O. este aceea că el trebuie să fie accesibil utilizatorului care îi poate cere o serie de
servicii în vederea realizării evoluţiei dorite a programului.
Privit prin prisma utilizatorului şi a programelor de aplicaţii, ansamblul de programe al
acestui tip de S.O. poate fi împărţit în două categorii:
- programe necesare în faza de pregătire, elaborare şi testare a programelor de aplicaţii
(editorul de texte, compilatorul, link-editorul, debuggerul etc.) numite, din acest motiv, şi
programe de serviciu;
- programe necesare în etapa de conducere, care se leagă cu programele utilizatorului în
faza de dezvoltare, formând aplicaţia dedicată care se implementează pe echipamentul de
conducere.
Pentru a nu încărca în mod nejustificat atât din punct de vedere hardware cât şi software
echipamentul de calcul destinat conducerii procesului industrial, dezvoltarea aplicaţiei se va face
pe un alt sistem numit sistem de dezvoltare care va conţine ambele categorii de programe.
4-6
subrutinele nu sunt întreruptibile, adică nu se acceptă întreruperea activităţii unei subrutine pentru
a trece la execuţia unui alt task. Acest lucru se datoreşte faptului că, în general, subrutinele
implică un timp de răspuns foarte mic, critic sau, altfel spus, sunt asociate unor evenimente
critice.
Există şi aşa numitele subrutine reentrante disponibile mai multor taskuri şi care pot fi
întrerupte deoarece nu sunt asociate unor evenimente critice.
Vom spune că două taskuri sunt paralele sau concurente dacă prima instrucţiune a unui task
demarează înainte ca ultima instrucţiune a celuilalt task să fi fost completată.
Dacă sistemul de calcul (conducere) este multiprocesor, paralelismul execuţiei taskurilor
poate fi asigurat în mod real în sensul că fiecare task poate fi executat de către un procesor. În
acest caz, se obţine o execuţie paralelă suprapusă în timp, numită şi execuţie paralelă fizică.
Dacă echipamentul de calcul este monoprocesor şi dotat cu un S.O. în timp real cu facilităţi
multitasking, execuţia paralelă a taskurilor se va face intercalat, pe principiul distribuirii timpului
unităţii centrale între taskuri ("time slicing"). La un moment dat, va deţine controlul procesorului
un singur task, dar datorită vitezei mari de lucru a acestuia, precum şi datorită modului de
programare se lasă impresia că taskurile se execută simultan, ca şi când fiecare task ar beneficia
de un procesor propriu - virtual, evident ceva mai lent. În acest caz, se spune ca are loc o execuţie
pseudo-paralelă sau o execuţie paralelă logică .
În cele ce urmează ne vom referi la acest din urmă mod de execuţie paralelă a taskurilor,
ceea ce corespunde situaţiei mai frecvent întâlnite în aplicaţiile de conducere şi supraveghere
automată a proceselor.
Pentru a putea realiza acest paralelism în prelucrarea taskurilor, arhitectura sistemelor de
calcul trebuie să conţină obligatoriu canale care să execute toate operaţiile de transfer de
informaţie, independent de procesor. Procesorul va avea doar rolul de a iniţia şi iniţializa operaţia
de I/E printr-un dialog adecvat cu canalul. În continuare canalul execută toate operaţiile de
transfer necesare, iar în încheiere semnalează procesorului, printr-un semnal de întrerupere, că şi-
a încheiat activitatea. Aceasta presupune existenţa unui sistem de întreruperi bine pus la punct.
Exemplu de execuţie a taskurilor în regim de multiprogramare
Considerăm cazul unui sistem în care există disponibile simultan trei taskuri T1, T2, T3.
Taskul T1 are prioritatea maximă, dar la iniţializarea sistemului, se presupune că este gata pentru
execuţie taskul T3.
Schematic, ocuparea de către cele trei taskuri a procesorului şi activitatea S.O. şi a canalelor
de I/E este reprezentată în următoarea diagramă.
4-7
Haşurat s-a reprezentat starea activă a unui task, a S.O. sau a CANAL-ului.
*** - reprezintă starea blocată a unui task, adică starea în care acesta nu poate fi executat,
fiind în aşteptarea unei resurse (pentru exemplul dat, resursa este un canal I/E).
------ reprezintă starea de întrerupere a unui task.
Iniţial, la pornirea sistemului, se execută programe specifice S.O. Acesta, va da la un
moment dat, controlul primului program gata de execuţie, adică taskului T3. La momentul (1),
taskul T3 iniţiază o operaţie de I/E. După ce transmite canalului toţi parametrii necesari executării
operaţiei de I/E, T3 trece în starea blocat pentru că aşteaptă rezultatele operaţiei de I/E iniţiate.
Aceasta conduce la preluarea controlului de către S.O., care va selecta acum taskul T1 (task care
are prioritate maximă în acest moment) căruia îi va da controlul.
La momentul (2) canalul lansează o întrerupere către procesor indicând încheierea operaţiei
de I/E iniţiată de taskul T3 ceea ce duce la suspendarea taskului T1 aflat în execuţie (trecerea lui
în starea întrerupt) controlul preluându-l S.O., care trece la o subrutină de tratare a întreruperii
sosite. După acceptarea şi tratarea întreruperii, taskul T3 trece din starea blocat în starea întrerupt.
Aceasta înseamnă că, din acest moment, execuţia taskului T3 poate fi reluată imediat ce se
încheie execuţia taskurilor de prioritate superioară.
După terminarea tratării întreruperii, la momentul (3) se reia execuţia taskului T1 pentru că
acesta este, în acest moment, de prioritate maximă. La momentul (4) şi taskul T1 lansează o
operaţie de I/E, după care trece în starea blocat, redând controlul S.O. Acesta va lansa în execuţie
la momentul (5) taskul cu prioritate maximă în acel moment, în cazul nostru taskul T2. După
terminarea operaţiei de I/E, canalul trimite, la momentul (6), un semnal de întrerupere, care
determină trecerea taskurilor T1 şi T2 în starea de întrerupere, controlul procesorului fiind preluat
de S.O. Acesta trece la subrutina de tratare a întreruperii generate de canal şi, după încheierea
tratării acesteia, dă controlul taskului T1 care are acum prioritate maximă. Terminarea execuţiei
taskului T1 determină reactivarea S.O. (momentul (7)), care va da controlul taskului T2, care la
terminarea execuţiei (momentul (8)) redă controlul S.O. Acesta reactivează taskul T3, iar după
terminarea acestuia (momentul (9)), controlul este preluat de S.O.
Din acest exemplu, se vede clar că în cazul programării paralele, un task este un ansamblu
indivizibil program-procesor.
În cadrul oricărui fel de execuţie paralelă există două categorii de taskuri peste un program
dat: taskuri disjuncte sau independente şi taskuri care interacţionează (sau care cooperează).
Două sau mai multe taskuri se numesc disjuncte dacă nu schimbă informaţii între ele sau
dacă nu utilizează resurse (zone de memorie, periferice etc.), în comun. În caz contrar, se spune
că ele interacţionează. Evoluţia unui program alcătuit numai din taskuri disjuncte este unică
indiferent de ordinea de execuţie a taskurilor. Dar, în cazul unei execuţii pseudo-paralele a două
sau mai multe taskuri peste un program dat, avem de-a face, în general, cu taskuri care
interacţionează.
Pentru o mai bună înţelegere a celor spuse prezentăm o serie de exemple.
Exemplul l: Fie o aplicaţie formată din trei taskuri: T1, T2, T3 având următoarea
componenţă:
Task T1 Task T2 Task T3
M1 = MAX(A, B) M2 = MAX(C, D) M = MAX(M1, M2)
Structura taskurilor este foarte simplă: T1 şi T2 calculează valoarea maximă dintre două
numere A, B, respectiv C, D, rezultatele fiind numerele M1, respectiv M2. Taskul T3 determină
maximul dintre M1 şi M2. Se observă imediat că taskurile T1 şi T2 sunt disjuncte, ordinea
execuţiei lor nealterând evoluţia în ansamblu a programului. Taskul T3, în schimb, cooperează cu
taskurile T1 şi T2 (preia valorile M1 şi M2 de la acestea) şi, ca atare, el trebuie să intre în
execuţie numai după terminarea execuţiei acestor două taskuri.
4-8
Ca urmare, ordinea de execuţie a taskurilor pentru o evoluţie corectă a programului dat va
fi: T1, T2, T3 sau T2, T1, T3, oricare altă ordine de execuţie având ca rezultat scăparea de sub
control a evoluţiei programului.
Exemplul 2: Fie o aplicaţie formată din două taskuri T1 şi T2.
Taskul T1 observă şi contorizează o serie de evenimente incrementând o variabilă
CONTOR. Taskul T2 tipăreşte ocazional numărul evenimentelor contorizate de taskul T1 şi după
fiecare tipărire anulează variabila CONTOR:
Task T1 Task T2
Observă evenimentul Tipareşte CONTOR
CONTOR = CONTOR + 1 CONTOR = 0
Se observă că cele 2 taskuri interacţionează între ele utilizând în comun variabila CONTOR
care se modifică în timp.
Dacă nu se iau măsuri speciale de programare, poate apare următoarea situaţie eronată:
presupunem că T1 a incrementat variabila CONTOR la 20, iar taskul T2 a tipărit aceaste cifre. Se
poate întâmpla însă ca înainte ca T2 să anuleze variabila CONTOR, taskul T1 să sesizeze un nou
eveniment şi să incrementeze variabila CONTOR de la 20 la 21. Rezultă deci că acest eveniment
se va pierde, el rămânând neraportat.
O altă situaţie, mai puţin evidentă, dar care conduce la rezultate eronate este următoarea:
Implementrea operaţiei CONTOR = CONTOR + 1 presupune existenţa mai multor
instrucţiuni în cod maşină:
- încarcă CONTOR în acumulator;
- incrementează acumulatorul;
- memorează conţinutul acumulatorului în CONTOR.
În timp ce taskul T1 execută această secvenţă, el poate fi întrerupt de T2 şi să se ajungă la
următoarea situaţie:
Presupunem că variabila CONTOR = 15 şi această valoare este încărcată în acumulator.
Considerăm că T2 tipăreşte valoarea 15 şi face CONTOR = 0. În continuare, taskul T1 adună 1 la
conţinutul acumulatorului şi memorează rezultatul 16 în CONTOR. Rezultă deci că au fost
raportate 15 evenimente, iar variabila CONTOR = 16 şi nu 0 cum ar fi trebuit să fie în mod
normal.
Exemplul 3: Se consideră 2 taskuri T1 şi T2 care scriu fiecare câte un mesaj pe consola
operatorului (display), folosind poziţionarea directă a cursorului în câte o poziţie (linie, coloană)
a consolei.
Task T1 Task T2
Poziţionează cursor în (L1,C1) Poziţionează cursor în (L2,C2)
Scrie MESAJ 1 Scrie MESAJ 2
MESAJ 1 şi MESAJ 2 sunt de fapt şiruri de caractere, iar (L1, C1) şi (L2, C2) numere de
linie şi coloană pe display (uzual, un display alfanumeric are 24 de linii şi 80 de coloane).
Dacă nu se iau măsuri speciale de protecţie, se poate ajunge la următoarea situaţie eronată:
taskul T1 preia controlul, poziţionează cursorul în linia şi coloana (L1, C1) şi începe să tipărească
MESAJ 1; dacă T1 este întrerupt înainte ca să fie terminată tipărirea lui MESAJ 1 şi controlul
este preluat de T2, acesta va poziţiona cursorul pe display în linia/coloana (L2, C2), va scrie
MESAJ 2, după care controlul revine lui T1, care continuă din punctul în care a fost întrerupt,
deci continuă tipărirea lui MESAJ 1; cursorul a rămas însă în poziţia lăsată de acţiunea taskului
T2 şi tipărirea lui MESAJ 1 este astfel compromisă.
Din aceste exemple rezultă clar că dacă nu se iau măsuri speciale de programare, în cazul
taskurilor care interacţionează, rezultatul nu poate fi prevăzut, aceasta datorită imposibilităţii
aprecierii momentului când se face transferul controlului.
4-9
Evoluţia unui program compus din astfel de taskuri nu este unică, ea depinzând de modul
de planificare al taskurilor spre execuţie, precum şi de timpul de execuţie al acestora. Pentru
obţinerea unei evoluţii dorite a programului, este necesară o programare foarte atentă care să
permită realizarea interacţiunii corecte între taskurile componente.
4 - 10
Fig. 4.3.
În zona rezervată sistemului de operare (SO) sunt plasate modulele rezidente ale SO sau
anumite module folosite temporar. Restul memoriei operative este disponibilă programelor
utilizatorului.
Suportul software pentru gestiunea memoriei în aceste sisteme este foarte redus. De regulă
se verifică dacă programele utilizator planificate pentru execuţie nu depăşesc capacitatea
memoriei operative disponibile în sistem (capacitatea MO - capacitatea zonei destinate SO). Dacă
se constată depăşirea capacităţii disponibile, se va emite un semnal de eroare, iar lucrarea
respectivă se va abandona. Mecanismele de protecţie a memoriei constau din procedee relativ
simple prin care se permite citirea informaţiei din zona aferentă SO şi interzicerea operaţiei de a
înscrie informaţii în această zonă. Sistemele de operare de acest tip se numesc monitor sau
supervizor . Funcţiile unui asemenea SO sunt:
1. Asigurarea continuităţii încărcării sistemumui. Aceasta înseamnă că în momentul în care
se termină execuţia unui task, controlul este preluat de supervizor, care iniţiază execuţia taskului
celui mai prioritar în acel moment, care preia şi controlul. Dacă taskul aflat în execuţie este
întrerupt (de un task mai prioritar), SO va suspenda execuţia taskului curent şi acesta, împreună
cu informaţia aferentă contextului când a fost întrerupt, va fi imediat transferat pe un suport de
memorie externă, în memoria operativă încărcându-se noul task ce urmează a fi executat.
Reluarea execuţiei taskului întrerupt se va face, după reîncărcarea acestuia în memorie, din
punctul în care a fost întrerupt.
2. Iniţierea şi achitarea operaţiilor de intrare-ieşire solicitate de programele utilizator.
3. Punera la dispoziţie, pentru programele utilizator, a unor rutine standard frecvent
utilizate.
Singura cale de a obţine accesul în zona aferentă SO de către programele utilizator constă în
apelul unor rutine ale SO.
Pprincipalul avantaj al acestei metode constă în simplitatea SO şi a spaţiului de memorie
mic ocupat de acesta, precum şi în faptul că se dispune pentru execuţia taskului curent de întregul
spaţiu al memoriei disponibile.
Dezavantajul metodei îl constituie timpul de răspuns mare datorat comutărilor frecvente
între taskuri sau de la un program la altul, deoarece transferul între memoria internă şi memoria
externă cere mult timp.
O metodă de a elimina acest dezavantaj constă în desemnarea unor taskuri critice pentru
care se impune un timp de răspuns minim, care rămân permanent într-o zonă protejată a memoriei
interne. De asemenea, utilizatorul are la dispoziţie un mecanism prin care va putea executa
programe, uneori cu mult mai mari decât spaţiul de adrese fizice disponibile. Acest mecanism se
numeşte metoda înlănţuirii şi suprapunerii (overlay) şi constă în suprapunerea unor module de
program. În acest caz, un program aplicativ sau un task aflat în execuţie controlează el însuşi
încărcarea de pe suportul extern a unor module de program sau taskuri. Încărcarea se face la
momente de timp bine definite impuse de evenimente externe sau interne, noile taskuri aducându-
se în memoria internă în zona proprie a programului apelant, putând să-l acopere parţial sau total.
Rezultă că programul de aplicaţie preia atât funcţia de planificare a execuţiei taskurilor, cât
şi de gestiune a memoriei interne, substituindu-se SO. Deşi această metodă presupune o
complicare a programului de aplicaţie, totuşi este foarte utilă pentru aplicaţii de complexitate
4 - 11
mică şi medie şi la care timpii de răspuns au valori foarte critice, precum şi în cazul sistemelor cu
divizarea timpului.
Dezavantajul esenţial al monoprogramării este acela că existând la un moment dat un singur
program în memorie, nu poate fi utilizat paralelismul între efectuarea operaţiilor de intrare-ieşire
şi operaţiile de prelucrare propriu-zise, ceea ce conduce la un timp de lucru global mult mai mare
şi un factor redus de utilizare a resurselor.
Cu toate acestea, această tehnică este foarte utilizată, mai ales, în cazul unor calculatoare de
putere mică şi medie destinate prelucrării unor lucrări cu caracter tehnico-ştiinţific. Astfel de
lucrări ocupă un timp îndelungat procesorul cu efectuarea unor operaţii aritmetice şi logice
complexe ceea ce face să se resimtă mai puţin influenţa timpului necesar schimbului informaţiei
între MO şi memoria externă.
Fig. 4.4.
Se observă că, şi în acest caz, o anumită zonă de memorie va fi alocată necesităţilor SO.
Fiecare partiţie va fi formată dintr-o zonă utilă în care se încarcă programele şi datele aferente
unui task şi o zonă neutilizată. În ceea ce priveşte protecţia memoriei, apar două aspecte:
1. Ca şi în cazul monoprogramării este necesar ca programele utilizator să nu afecteze în
nici un fel informaţiile din zona SO.
2. Se impune ca execuţia unui program (task) să nu afecteze în nici un fel celelalte
programe (taskuri) cu care coexistă în memorie.
Un mecanism uşor de implementat care să răspundă cerinţelor de mai sus îl reprezintă
mecanismul cheie de protecţie - cheie de acces. Conform acestui mecanism, fiecărei partiţii i se
asociază, utilizând mijloace hardware, o cheie de protecţie. Când procesorul este alocat unui
program (task), câmpul din tabela de stare a taskului ce conţine cheia de acces la memorie va fi
actualizat corespunzător partiţiei programului curent aflat în execuţie. În timpul execuţiei, la
4 - 12
fiecare acces la memorie se verifică egalitatea cheii de acces cu cea a cheii de protecţie, accesul
fiind permis numai în partiţiile unde se înregistrează egalitatea.
Mecanismul cheie de protecţie - cheie de acces poate fi extins uşor şi la canalele de intrare-
ieşire.
Dacă memoria operativă este divizată în partiţii înainte de execuţia oricărei lucrări, se spune
ca lucrăm cu partiţii statice (fixe). În acest caz dimensiunea partiţiei este fixată încă din etapa de
generare a SO.
Într-o asemenea organizare, un program (task) dintr-o partiţie este executat până în
momentul în care va iniţia o operaţie de intrare-ieşire. Evident că cel care iniţiază propriu-zis
operaţia de intrare-ieşire este SO.
După iniţierea operaţiei de intrare-ieşire, SO va trece controlul unui alt task rezident în altă
partiţie a memoriei şi care dispune de toate resursele necesare cu excepţia procesorului. La fel se
petrec lucrurile şi în cazul în care un task este întrerupt de un task mai prioritar sau ca urmare a
apariţiei unui eveniment în proces: SO va da controlul taskului mai prioritar sau se trece la rutina
de tratare a întreruperii solicitate. Dacă într-o fază a lucrării cantitatea de memorie solicitată
depăşeste cantitatea de memorie ce poate fi pusă la dispoziţie într-o partiţie, întreaga lucrare se
abandonează.
Modul de alocare a memoriei cu partiţii fixe este indicat în situaţia în care se cunosc
dimensiunile programelor (taskurilor) şi zonele de memorie ocupate de datele pe care acestea le
vehiculează. În acest caz partajarea memoriei se va face în funcţie de necesităţi, obţinând deci o
bună utilizare a memoriei.
Dacă partiţiile sunt create nu la generarea sistemului, ci chiar în timpul execuţiei lucrării,
înaintea începutului fiecărei faze a lucrării, se spune că sistemul de calcul lucrează cu partiţii
dinamice. În această situaţie SO poate ajusta dimensiunea partiţiilor în funcţie de necesităţile
curente. Uneori aceste modificări se realizează chiar în timpul execuţiei unor programe prin
extensia sau reducerea memoriei alocate acestor programe. SO poate modifica şi numărul
partiţiilor existente la un moment dat în memorie. Aceste apecte impun ca SO să deţină informaţii
detaliate despre organizarea memoriei sub forma a două tabele: una, pentru partiţiile alocate şi
alta, pentru partiţiile libere. Informaţiile ce se păstrează în aceaste tabele se referă la dimensiunile
partiţiilor, adresa primei locaţii a partiţiei, rectricţiile de acces la fiecare partiţie.
Cele mai cunoscute procedee de alocare dinamică a memoriei sunt: procedeul FIRST FIT
(procedeul primei partiţii) - eficient în cazul programelor de dimensiuni mari şi procedeul BEST
FIT (procedeul celei mai bune partiţii) - specific în cazul unor programe mici şi cu o mare
diversitate. Alte algoritme de alocare dinamică a memoriei sunt: algoritmul înjumătăţirii
(BUDDY SYSTEM), care impune ca fiecare partiţie liberă să aibe o dimensiune egală cu o putere
a lui 2, algoritmul numerelor lui Fibonacci, care presupune o divizare a memoriei proporţională
cu numerele din şirul lui Fibonacci etc.
Deoarece alocarea dinamică a memoriei duce la apariţia unor fragmente de memorie
neutilizate, în general de dimensiuni mici, ceea ce duce la amânarea introducerii în execuţie a
unor lucrări noi până la terminarea unei lucrări în curs de execuţie ce eliberează o partiţie
suficientă de memorie, este necesar ca, periodic, aceste regiuni libere să fie combinate într-o
regiune mai mare, operaţie numită compactare sau recompactare a memoriei. Operaţia este foarte
costisitoare deoarece presupune deplasarea programelor în memorie, cu modificarea tuturor
adreselor (mai puţin adresele porturilor dispozitivelor de intrare-ieşire) şi se realizează printr-un
mecanism comun software-hardware.
Principalul avantaj al alocării dinamice, în special în cazul folosirii programelor relocabile
(adică programe ce conţin adrese relative după faza de editare a legăturilor) îl constituie
eliminarea fragmentării memoriei, cea ce duce la o utilizare mult mai eficientă a MO şi la un grad
superior de multiprogramare.
4 - 13
Dezavantajul constă în folosirea unor componente hardware suplimentare, reducerea vitezei
de lucru datorită timpului necesar pentru calculul adreselor efective şi creşterea timpului efectiv
de lucru datorită timpului mare necesar compactării memoriei, în special dacă această operaţie se
realizează frecvent.
Menţionăm că metoda este mai puţin utilizată în cazul SO cu divizarea timpului.
4 - 14
Fig. 4.5.
Un task ACTIV poate fi, la rîndul lui, în una din următoarele substări: BLOCAT
(BLOCKED), GATA DE EXECUŢIE (READY) sau ÎN EXECUŢIE (RUN).
Un task neinstalat este un task creat rezident pe un suport extern sau în memoria internă a
calculatorului, dar care nu a fost încă adus la cunoştinta sistemului de operare
(EXECUTIVULUI). Un task creat este făcut cunoscut sistemului de operare prin operaţia de
instalare, în urma căreia el este trecut automat în starea INACTIV.
Un task se află în starea INACTIV dacă este instalat, dar nu este planificat pentru execuţie.
Prin instalare se creează şi i se alocă taskului un vector de stare sau un bloc de control al
taskului care reprezintă materializarea taskului în sistem şi care conţine informaţiile specificate
mai sus.
Vectorii de stare ai taskurilor sunt grupaţi într-o tabelă a taskurilor care este folosită de
sistemul de operare cu ocazia instalării şi distrugerii (ştergerii) taskurilor, precum şi pentru
efectuarea schimbărilor survenite în starea taskurilor pe parcursul duratei lor de existenţă.
Taskului i se atribuie un nume sau un număr care permite sistemului de operare şi altor
taskuri să-l desemneze fără ambiguitate pe toată durata lui de existenţă.
Un task poate reveni în starea NEINSTALAT numai din starea INACTIV prin operaţia de
ştergere (sau distrugere) a lui, dezafectîndu-i-se vectorul de stare.
Un task pentru care se face o cerere de intrare în execuţie trece din starea INACTIV în
starea ACTIV şi anume în substarea READY, tranziţia 1, adică are îndeplinite toate condiţiile şi
poate astfel concura la ocuparea procesorului. Momentul trecerii unui task în substarea GATA
DE EXECUŢIE nu poate fi prevăzut cu exactitate de către programator, acest moment fiind
funcţie de complexitatea aplicaţiei şi de modul în care se face planificarea taskurilor pentru
intrarea lor în execuţie. Precizăm că planificarea taskurilor pentru execuţie este realizată de un
modul al sistemului de operare numit planificator (SCHEDULER).
Trecerea unui task în substarea ÎN EXECUŢIE (RUN) se face numai din substarea
READY, tranziţia 2. Există două tehnici de bază pentru realizarea planificării taskurilor spre
execuţie:
10. Procedeul round-robin, prin care taskurile aşezate într-o coadă de aşteptare sunt
executate succesiv, fie până la terminarea lor normală, fie un interval (cuantă) de timp Δt bine
4 - 15
determinat. Strategia de administrare a cozii este de tip FIFO (First In - First Out : Primul venit -
Primul ieşit). După ce un task a fost executat, acesta este trecut în coada de aşteptare şi este lansat
în execuţie taskul următor. Dacă taskul nu se termină în timpul alocării curente, el este trecut prin
coada de aşteptare de n ori, unde n este cel mai mic întreg care satisface relaţia t ≤ n × Δt unde Δt
este cuanta de timp alocată rulării curente a unui task, iar t este timpul de execuţie al taskului. De
obicei, parametrul Δt se alege astfel încât majoritatea interacţiunilor utilizator-sistem să se
termine într-o singură cuantă (de regulă de ordinul milisecundelor). Se observă că, acest algoritm
întrerupe un task în curs de execuţie indiferent dacă la epuizarea cuantei de timp acordate taskul
respectiv s-a terminat sau nu.
20. Procedeul după priorităţi, prin intermediul căruia fiecărui task îi este atribuit un
indicator de importanţă materalizat printr-un număr numit prioritate, iar dintre taskurile gata de
execuţie, la un moment dat, care concură la ocuparea procesorului, sistemul de operare va aduce
ÎN EXECUŢIE taskul cu prioritatea cea mai mare la acel moment.
Observaţii:
1. În cazul EXECUTIVELOR care permit ambele moduri de planificare a taskurilor pentru
execuţie, procedeul round-robin se aplică taskurilor de aceeaşi prioritate.
2. Există sisteme de operare evoluate care oferă posibilitatea de activare a taskurilor în
condiţii de criză de timp şi care dispun de proprietatea remarcabilă de creştere automată a
priorităţii unui task dacă acesta nu a fost executat într-un anumit interval de timp.
3. Este evident că pe un sistem de calcul monoprocesor, la un moment dat, un singur task se
află ÎN EXECUŢIE.
Trecerea unui task dintr-o stare în alta se poate realiza, de asemenea, în două moduri:
10. Prin intermediul întreruperilor determinate de evenimentele interne sau externe generate
prin intermediul sistemului de întreruperi, contextul comutării fiind determinat de nivelul
întreruperii şi de subrutina de tratare a acesteia. Evenimentele ce sunt luate în considerare de
sistem sunt:
- întreruperi de la procesul condus;
- întreruperi de la ceasul de timp real;
- întreruperi generate de dispozitivele de intrare-ieşire;
- întreruperi iniţiate de operator de la COP;
- terminarea sau suspendarea executării unui task activ.
20. Prin directive (cereri de servicii) către sistemul de operare (EXECUTIV) din taskul care
se află în execuţie, contextul comutării fiind determinat de tipul directivei şi de parametrii
acesteia.
Un sistem de operare în timp real trebuie să permită ambele procedee de comutare a
taskurilor, aceasta şi datorită faptului că directivele folosesc implicit sistemul de întreruperi al
microprocesorului.
Mai mult, un EXECUTIV de timp real este necesar să fie însoţit de un MONITOR care să
constituie interfaţa între operator şi programul ce reprezintă aplicaţia de conducere şi care să
conţină comenzi având acelaşi efect asupra taskurilor ca şi directivele. Astfel, prin intermediul
MONITORULUI, operatorul se poate informa asupra stării taskurilor, poate realiza, dacă este
necesar, modificarea stării acestora, acţiuni necesare, mai ales, în faza de dezvoltare şi depanare a
programului.
Celelalte tranziţii ale unui task dintr-o stare în alta au loc în următoarele condiţii:
- Tranziţia 3 din substarea RUN în starea INACTIV apare în mod logic (sau normal) la
terminarea taskului.
- Tranziţia 4 din substarea RUN în substarea READY se realizează în două situaţii:
4 - 16
a) taskul curent este întrerupt de un alt task, de un task critic, mai prioritar, apărut în
condiţii de context extern sau intern;
b) în cazul modului de prelucrare a taskurilor în regim de time sharing (cu divizarea
timpului), când cuanta de timp alocată execuţiei taskului curent s-a epuizat, deşi el dispune în
continuare de toate resursele necesare execuţiei sale.
- Trecerea din substarea RUN în substarea BLOCKED, tranziţia 5, se realizează în situaţia
în care taskul aflat în execuţie este întrerupt pentru îndeplinirea uneia dintre următoarele condiţii:
a) terminarea unei operaţii de intrare-ieşire solicitată de task;
b) apariţia unui eveniment extern;
c) trecerea unui anumit interval de timp.
- Un task trece din substarea BLOCKED în substarea READY, tranziţia 6, când cauzele
care au produs blocarea execuţiei taskului au fost înlăturate, adică sunt îndeplinite condiţiile:
a) s-a încheiat operaţia de intrare-ieşire iniţiată de task;
b) s-a eliberat o zonă de memorie internă suficientă pentru a permite execuţia taskului;
c) a avut loc evenimentul extern aşteptat;
d) a expirat intervalul de timp de aşteptare.
- Tranziţia 7 din substarea READY în substarea BLOCKED apare în situaţia când un task
ce era gata de execuţie este trecut în substarea BLOCAT de un task aflat în execuţie, sau nu mai
poate fi executat din considerente că nu mai dispune de suficientă memorie internă.
- De asemenea, un task în execuţie poate trece, prin terminare forţată, în starea INACTIV
atât taskuri aflate în substarea READY, tranziţia 8, cât şi taskuri aflate în substarea BLOCKED,
tranziţia 9.
Observaţie: Prin terminare forţată, unui task activ i se suspendă toate condiţiile de
aşteptare şi i se retrage orice posibilitate de alocare a unei resurse.
Trebuie făcută menţiunea că dacă un task pierde controlul procesorului rămânând în starea
ACTIV, reluarea execuţiei lui se va face din punctul în care a fost întrerupt. Pentru ca reluarea
execuţiei să se facă în contextul întreruperii taskului este necesar ca, în momentul întreruperii
unui task, sistemul de operare să asigure salvarea întregului context aferent taskului, adică
conţinutul registrelor generale ale unităţii centrale, conţinutul registrului indicatorilor de stare etc.
Dacă comutarea stării taskurilor se face sub controlul unui EXECUTIV de timp real prin
intermediul directivelor, în urma lansării unei directive, controlul procesorului este transferat de
la taskul aflat în execuţie (taskul care a lansat directiva) către EXECUTIV pentru ca acesta să
satisfacă imediat cererea conţinută în directivă. Din punct de vedere al returnării controlului de
către EXECUTIV către taskurile componente aplicaţiei distingem două categorii de directive:
- Directive pe care EXECUTIVUL le satisface returnând apoi controlul taskului care a dat
directiva (care a lansat cererea de servicii);
- Directive care cer o serie de servicii EXECUTIVULUI, după satisfacerea cărora acestea
nu mai returnează controlul taskurilor apelante ci, determină o nouă replanificare (rescheduling) a
taskurilor pentru execuţie. EXECUTIVUL va aduce în execuţie taskul gata de execuţie cu
prioritatea cea mai mare. În acest caz, se spune că directiva declară eveniment semnificativ .
Structura generală a unui task executat sub controlul unui EXECUTIV de timp real este
prezentată în Fig. 4.6.
4 - 17
Fig. 4.6.
4 - 18