Dezactivarea intreruperilor
Cea mai simpla solutie este sa facem ca fiecare proces sa dezactiveze toate intreruperile imediat ce a intrat in zona critica si sa le activeze chiar inainte de a o parasi. Cu aceasta metoda nu pot aparea intreruperi cauzate de ceas. Processorul este schimbat intre procese doar ca urmare a intreruperilor produse de ceas sau din alte motive si daca intreruperile sunt dezactivate procesorul nu va fi alocat altui proces. Astfel odata ce un proces a dezactivat intreruperile, poate sa analizeze si sa actualizeze memoria comuna fara ca alt proce sa intervina.
In general aceasta abordare nu este prea agreata deoarece nu este intelept sa I se acorde unui proces utilizator puterea de a dezactiva intreruperile. Sa presupunem ca unul dintre procese chiar ar face acest lucru si nu le-ar mai activa inapoi. Ar putea insemna sfarsitul sistemului. In plus, daca sistemul are doua sau mai multe procesoare, dezactivarea intreruperilor afecteaza doar procesorul care a efectuat comanda de dezactivare. Celelalte vor continua sa ruleze si vor putea sa acceseze memoria comuna.
Pe de alta parte, este adesea convenabil pentru kernel sa dezactiveze intreruperile pentru cateva instructiuni in timp ce actualizeaza variabile sau liste. Daca s-ar produce o intrerupere, de exemplu intr-un moment in care lista proceselor pregatite este intr-o stare intermediara, ar putea sa apara conditii de competitie. Concluzia este urmatoarea: adesea dezactivarea intreruperilor este o tehnica utila in cadrul sistemului de operare, dar nu este potrivita ca mecanism general de excludere reciproca pentru procesele utilizatoare.
Ca o a dou-a incercare, sa cautam o solutie software. Sa zicem ca avem o singura variabila impartita,variabila (inchisa),initial 0. Cind un proces vrea sa intre in regiunea lui critica, mai intii verifica inchizatoarea. Daca inchizatoarea este 0, procesul o seteaza la 1 si intra in regiunea critica. Daca inchizatoarea . este deja 1, procesul asteapta pina ea devine 0. Deci,un 0 inseamna ca procesul este in regiunea lui critica, iar un 1 inseamna ca unele procese sunt in regiunea lor critica.
Din pacate, aceasta idee contine exact acelasi (flow) fatal pe care l-am intilnit la directorul (spooler). Sa presupunem ca un proces citeste inchizatoarea. si vede ca este 0. Inainte de a seta inchizatoarea. la 1, un alt proces este programat, ruleaza, si seteaza inchizatoarea. la 1. Cind primul proces ruleaza din nou,si el la rindul lui va seta inchizatoarea la 1, si astfel doua procese vor fi in regiunea lor critica in acelasi timp.
Acum puteti gindi ca am putea trece peste aceasta problema citind mai intii valoarea inchizatorii. apoi verificind-o inca o data chiar inainte de a o implementa, dar acest lucru chiar nu ajuta. Problema. se pune acum daca al doi-lea proces modifica inchizatoarea chiar dupa ce primul proces a terminat a doua lui verificare.
O a treia abordare a problemei este prezentata in fig.2-8. Aceasta sectiune de program, este scrisa in C. C a fost aleasa aici pentru ca adevaratele sisteme. de operare. sunt scrise toate in C ( sau C++), dar rareori in Modula 2 sau Pascal.
while (TRUE) { while (TRUE) {
while (turn !=0) /*wait*/; while (turn !=1)/*wait*/;
critical_region(); critical_region();
turn=1; turn=0;
noncritical_region(): noncritical_region();
} }
-
(b)
Fig. 2-8. O posibila solutie la pb. regiunii critice.
In Fig.2-8, variabila integer turn, initial 0, urmareste al cui rind este de a intra in regiunea critica si examineaza sau reactualizeaza memoria inpartita. Initial, procesul 0 (inspects) turn, o gaseste a fi 0, si intra in regiunea lui critica. Procesul 1 o gaseste si el a fi 0 si de aceea sta intr-un (loop) strins testind continuu turn pt. a vedea cind devine 1. Testarea continua a variabilei pina cind apare o valuare se numeste asteptarea ocupata. Normal s-ar evita, din moment ce ocupa timpul unitatii centrale de prelucrare sau a UCP sau cum vrei tu…Doar atunci cind avem o asteptare motivata ca asteptarea va fi scurta este (busy waiting used).
Cind procesul 0 paraseste regiunea lui critica, seteaza turn la 1, pt. a permite proc.1 sa intre in reg. lui critica. Presupunem ca procesul 1 termina reg. lui critica mai repede, deci ambele procese sunt in regiunile lor noncritice, cu turn setat la 0.Acum procsel 0 i-si executa intreg (loop) repede, revenind la regiunea lui noncritica cu turn setat la 1. In acest moment procesul 0 I-si termina regiunea noncritica si se intoarce in vf.(loop-ului). Din pacate, nu I se permite sa intre in reg. lui critica acum, pt. ca turn este 1 si procesul 1 este ocupat cu reg.lui noncritica. Altfel spus, a face ture nu este o idee prea buna cind unul din procese este mult mai incet decit celalalt.
Situatia violeaza conditia 3 (..):proc.0 este blocat de catre un procf. Care nu este in reg. lui critica. Revenind la disc.despre dir (spooler), daca acum acum asociem regiunii critice citirea shi scrierea dir.(spooler), procesului 0 nu I se va permite sa printeze alt fishier pt. ca proc.1 facea altceva.
Defapt, aceasta solutie cere ca cele doua procese sa alterneze strict in intrarea lor in reg. lor critice, de ex.,in fishierele(spooling). Nici unuia nu I se va permite sa (spool) doua intr-un rind. Cind acest algoritm evit toate cursele(races),nu este un candidat serios ca o solutie pt. ca violeaza conditia3.
Combinind ideea de a face ture cu ideea variabilelor inchise si a var. avertisment, un matematician (de pe pamint), T.Dekker, a fost primul care a (devise) o solutie softwere de pb. excluderii mutuale cera nu are nevoie de alternanta stricta. Vezi (Dijkstra,1965).
In 1981, G.L.Peterson a descoperit un mult mai simplu mod de a ajunge la (mutual exclusion), facind astfel solutia lui Dekker depasita. Alg. Lui Peterson este ilustrat in fig.2-9. Acest alg. Consta in doua proceduri scrise in ANSI C, ceea ce inseamna ca (function portotypes) ar trebui alimentati pentru toate functiunile definite shi folosite. Totusi, pt. a economisi spatiu,nu vom arata prototipele in acest alte exemple.
Inainte de a folosi vasiabilele impartite,fiecare proces cheama regiunea de intrare cu propriul lui nr. Procesat, 0 sau 1, ca parametri. Aceasta chemare o va face sa astepte, daca este nevoie, pina este in siguranta sa intre. Dupa ce a terminat cu variabila shared, procesul cheama sau se adreseaza regiunii_de_plecare pt. a indica ca este gata,si sa lase alt proces sa intre,daca este nevoie.
Sa vedem,dar, cum aceasta metoda functioneaza. Initial nici un proces nu este in regiunea lui critica. Acum procesul 0 cheama regiunea de intrare. Va ramine acolo pina interested [0] ajunge la FALSE, un evenument care se intimpla cind procesul 0 cheama regiunea de intrare aproape simultan. Amindoua vor stoca nr.lor de procesare in turn. Oricare implementare este facuta, ultima este cea care conteaza;prima este pierduta. Sa presupunem ca proc.1 implem. Ultimul, deci turn este 1. Cind amindoua proc. Ajung la declaratia while, proc. 0 se executa de 0 ori si intra in regiune lui critica. Procesul 1 (loops) si nu intra in regiunea lui critaca.
D. Repaus si repornire
Atat solutia data de Peterson cat si solutia cu utilizare TSL sunt corecte, dar ambele au defectul ca necesita asteptare activa. In principal, aceste solutii fac urmatorul lucru: cand un proces vrea sa intre in zona sa critica, verifica daca intrarea este permisa. Daca nu este, procesul ramane intr-o bucla stransa asteptand permisiunea.
Aceasta abordare nu numai ca iroseste timpul procesorului, dar poate sa aiba si efecte neasteptate. Sa ne gandim la un computer cu doua procese: H, cu o prioritate ridicata si L, cu o prioritate scazuta. Regulile de temporizare spun ca H sa fie rulat de fiecare data cand este pregatit. La un moment dat, cand L se afla in zona critica, H este pregatit sa fie rulat (ex. se incheie o operatie I/O). H intra in asteptare activa, dar de vreme ce L nu este niciodata temporizat in timp ce H este rulat, L nu maiare ocazia s paraseasca zona critica, asa ca H va ramane in bucla. Aceasta situatie se mai numeste si problema inversarii prioritatii.
Acum sa analizam cateva comunicari interprocesorale simple care se blocheaza in loc sa iroseasca timpul procesorului atunci cand nu li se permite accesul in zona lor critica. Una dintre cele mai simple este perechea repaus si pornire (SLEEP si WAKEUP).SLEEP este un apel al sistemului care produce blocarea apelantului, adica suspendarea lui pana cand un alt proces este pornit. Apelul WAKEUP are un parametru, pornirea procesului. Alternativ, atat SLEEP cat si WAKEUP au fiecare cate un parametru, o adresa de memorie utilizata pentru a potrivi comenzile SLEEP si WAKEUP.
Dostları ilə paylaş: |