Sunteți pe pagina 1din 5

51.

Modelul producătorului şi consumatorului


O schemă uzuală de comunicare este cea în care un proces (producătorul) trimite mesaje unui alt proces
(consumatorul), utilizând un tampon î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 trebuie să poată fi pierdut; dacă tamponul conţine N mesaje nepreluate, nu pot fi depozitate aici
mesaje suplimentare,
 o operaţie “imposibilă” (depozitare într-un tampon plin sau 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);
Monitorul tampon poate fi elaborat, transcriind în mod direct autorizările de depăşire:
tampon : monitor;
var n : 0..N;
non_plin, non_vid : condiţie;
<declaraţii ale procedurilor depozitare şi preluare>
procedura depozitare(m:mesaj);
begin
if n=N then
non_plin.aşteptare
endif;
n:=n+1;
introducere(m);
non_vid.semnalizare
end
procedura preluare(var m:mesaj);

begin
if n=0 then
non_vid.aşteptare
endif;
preluare(m)
; n:=n-1;
non_plin.semnalizare
end;
begin -- iniţializare
n:=0;
end
end tampon
Procedurile introducere(m) şi preluare(m) definesc politica de gestionare a tamponului şi
reprezentarea internă a mesajelor. Un caz frecvent este acela în care mesajele sunt reprezentate de
elementele succesive ale unui tablou, administrat în mod circular. În acest caz mesajele sunt preluate
în ordinea depozitării. Procedurile de gestionare a tamponului se vor scrie astfel:
type mesaj : <descrierea formatului
mesajelor> ptr : 0..N-1;
var fa : array[ptr] of
mesaj; top, coadă: ptr;
procedura intrare(m:mesaj);
begin
fa[coadă]:=m;
coadă:=coadă+1 mod
N end;
procedura ieşire(var m:mesaj);
begin
m:= fa[top];
top:=top+1 mod
N end;
<iniţializarea se va completa cu top:=0; coadă:=0;>

Această schemă poate fi extinsă pentru mai mulţi producători şi consumatori. Drept efect, procedurile monitorului
asigură accesarea exclusivă la mesaje între producători şi consumători. Totuşi, în cazul a mai mulţi consumatori schema
nu permite direcţionarea unui mesaj către un consumator anumit: putem doar garanta, că un mesaj va fi preluat de un
consumator (şi numai de unul singur) fără a specifica concret de care.

52. Primitive de comunicare


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)
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
În conformitate cu nivelul de exprimare la care este definit mecanismul de comunicare, mesajele pot fi specificate
de un tip, analogic obiectelor unui limbaj sau prin lungimea fizică a lor. 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. Schema a doua facilitează modificarea dinamică a interconexiunilor proceselor sau chiar componentele
unei mulţimi de procese, care comunică.
Î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. Este posibilă şi situaţia inversă când un proces
poate fi asociat la mai multe porţi distincte. Dacă asocierea între procesul receptor şi poartă este statică, un nume de
poartă specifică fără ambiguitate un proces receptor ca şi în metoda desemnării directe.
3) Moduri de sincronizare
Pentru primitivele de comunicare pot fi specificate mai multe moduri de sincronizare. În caz general, operaţia de
recepţie blochează, în absenţa mesajului, receptorul. Unele sisteme pun la dispoziţie primitive care dau posibilitatea să
se determine dacă o cutie poştală este vidă, ceea ce permite evitarea blocării. Pentru emitere sunt utilizate două moduri
de sincronizare:
 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. Folosirea tampoanelor de lungime variabilă cu alocarea
dinamică a locaţiunilor reduce probabilitatea blocării emiţătorului.
 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.
Ultima situaţie nu este totdeauna detectabilă. O tehnică uzuală constă în stabilirea unui interval de timp maxim de
aşteptare a unui mesaj şi deblocarea procesului care aşteaptă la expirarea acestui interval (v. 3.4.5).
Vom ilustra prin câteva exemple reprezentative utilizarea acestor mecanisme de comunicare.
Exemplul 3.12. Sistemul de operare Thoth [8]. În acest sistem comunicarea foloseşte desemnarea directă şi sincronizarea prin rendez-vous. Mesajele
sunt de lungime constantă. Sunt utilizate patru primitive:
id:=send(message, id_dest)
emite procesului id_dest un mesaj; blochează emiţătorul până la primirea unui răspuns, transmis în message. Această primitivă
indică identitatea procesului care a transmis răspunsul (sau nil, dacă destinatarul nu există).
id:=receive(message, id_orig)
recepţionează un mesaj; procesul origine poate să nu fie specificat. Valoarea transmisă este identitatea emiţătorului.
reply(message, id_orig, id_dest)
trimite un răspuns destinatarului specificat (care trebuie să-l aştepte); nu este blocantă; fără consecinţe, dacă răspunsul nu
era aşteptat.
forward(message, id_orig, id_dest)
această operaţie non blocantă este utilizată de un proces după recepţionarea unui mesaj trimis de către id_orig, pentru ca să
impună mesajul să ajungă la id_dest, care are acum obligaţia de a răspunde lui id_orig. ◄
Exemplul 3.13. Sistemul de operare Unix [9]. În sistemul Unix comunicarea între procese utilizează tampoane, numite pipes (tuburi), administrate
conform schemei producător-consumator. Mesajele transmise sunt caractere. Un pipe (tub) leagă un emiţător şi un receptor,
conexiunea fiind stabilită dinamic. ◄
Exemplul 3.14. Rendez-vous în limbajul de programare Ada [10, 11]. Limbajul Ada permite definirea proceselor. Forma sintactică
a comunicărilor între procese este apelarea procedurii, însă transmiterea parametrilor şi a rezultatelor are loc
conform principiului de transmitere a mesajelor cu rendez-vous. Recepţionarea poate fi condiţionată (un apel
este acceptat doar dacă o condiţie specificată este satisfăcută) şi există posibilitatea de aşteptare multiplă. ◄

53. Aplicaţii : relaţia client-server


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)]
Secvenţele din parantezele pătrate sunt facultative.
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.
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.
Fără a modifica schema de mai sus putem introduce mai multe procese server echivalente, oricare
dintre ele fiind în stare să satisfacă o cerere a unui serviciu. Aceste servere în recepţie vor fi asociate la
una şi aceeaşi cutie poştală.
Modelul din 3.4.2.1 (alocarea resurselor banalizate) şi modelul client-server de mai sus sunt
reprezentative pentru două scheme de obţinere a unui serviciu cu ajutorul proceselor într-un sistem de
operare: apelarea de procedură într-un monitor sau activarea uni proces server ciclic prin emiterea
mesajelor. Alegerea între aceste două scheme este dictată de considerente de eficacitate (schema
serverului este preferată, atunci când există paralelism real între client şi server) sau de uniformitate a
structurii.

54. Implementarea sincronizării. Administrarea intrărilor-ieşirilor


55. Implementarea sincronizării. Administrarea unui periferic
56. Implementarea sincronizării. Buferizarea imprimării
57. Implementarea sincronizării. Sincronizarea temporală
58. Gestionarea dinamică a proceselor
59. Sincronizarea în Windows
60. Procese şi fire în Windows
61. Necesitatea sincronizării în Windows
62. Structura mecanismului de sincronizare în Windows
63. Administrarea obiectelor de sincronizare în Windows
64. Excluderea mutuală în Windows
65. Evenimentele în Windows
66. Semafoarele în Windows
67. Secţiunile critice în Windows
68. Protejarea accesării variabilelor în Windows
69. Sincronizarea în MFC
70. Exemplu de sincronizare în Windows
71. Utilizarea secţiunilor critice în Windows
72. Structura RTL_CRITICAL_SECTION în Windows
73. Funcţii API pentru secţiunile critice în Windows
74. Clase de secţiuni critice în Windows
75. Depanarea secţiunilor critice în Windows

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