teza barbier

Upload: iurii-rusu

Post on 15-Jul-2015

164 views

Category:

Documents


0 download

TRANSCRIPT

CuprinsCuprins..................................................................................................2 INTRODUCERE........................................................................................3 1. GESTIUNEA PROCESELOR....................................................................4 1.1. Definiia procesului...........................................................................................4 1.2. Comutarea proceselor......................................................................................6 1.3. Procese n UNIX................................................................................................7 2. PROBLEME CLASICE DE COORDONARE i SINCRONIZARE A PROCESELOR ...........................................................................................................13 2.1. Cina filozofilor (The Dining philosophers problem).........................................13 2.2. Problema cititorilor i scriitorilor.....................................................................14 2.3. Problema brbierului somnoros......................................................................15 ...........................................................................................................18 3.PARTEA PRACTIC.............................................................................19 3.1. Descrierea algoritmului elaborat....................................................................19 3.2.Listingul programului.......................................................................................23 3.3.Rezultate obinute...........................................................................................26 CONCLUZII ..........................................................................................29 BIBLIOGRAFIE.......................................................................................30

2

INTRODUCERE Informatica este o tiin recent i nu a avut nc timp s se structureze pe capitole strict delimitate i bine definite. Dezvoltarea exploziv din ultimele dou decenii a fcut ca ordonarea materialului s urmreasc cu greu abundena de noi informaii att n domeniul tehnicii de calcul ct i n privina numeroaselor probleme n rezolvarea crora aceasta poate fi utilizat. Pe plan didactic, ns, s-au conturat anumite discipline care s asigure studenilor posibilitatea de a accede la problematica vast a informaticii. Printre altele se studiaz i SISTEMELE DE OPERARE care intervin ntr-un sistem de calcul. Definiia: Un sistem de operare (SO) este un set de programe care are dou roluri primordiale: - asigur o interfa ntre utilizator i sistemul de calcul, extinznd dar i simplificnd setul de operaii disponibile; - asigur gestionarea resurselor fizice (procesor, memorie intern, echipamente periferice) i logice (procese, fiiere, proceduri, semafoare), implementnd algoritmi destinai s optimizeze performanele. De exemplu, cele dou componente ale definiiei pot fi: publicitatea (interfaa) i valoarea produsului (gestionarea resurselor). Exemple de SO sunt sistemele MS-DOS, WINDOWS i UNIX. n lucrarea dat n primul capitol am realizat un studiu proceselor din sistemul de operare anume din Linux studiind metodele de comutare a proceselor, de creare i terminare. Pentru a vedea toate momentele de execuia unui proces am prezenta acest lucru printr-o schema. n capitolul doi am studiat Problemele clasice de comunicare ntre procese anume: 1. Problema filosofilor (problema de sincronizare). 2. Problema cititorilor i scriitorilor. 3. Problema frizerului. 4. Problema productor-consumator. ns innd cont de tema mea mai mult m-am aprofundat n studierea Problemei frizerului iar dup un studiul amnunit a acestei probleme am elaborat o aplicaie care lucreaz dup acest algoritm prezentnd eficiena lui n practic.

3

1. GESTIUNEA PROCESELOR 1.1. Definiia procesului ntr-un sistem de calcul, un proces este un program n execuie; este deci o entitate activ (dinamic) a sistemului de operare i constituie unitatea de lucru a sistemului. nelegerea diferenei ntre un program i un proces este important . Andrew Tannenbaum, al crui tratat este baza documentrii pentru specialitii n SO, folosete o analogie pentru sesizarea acestei diferene. S considerm un savant care coace un tort pentru aniversarea fiicei sale. Are reeta tortului i o buctrie utilat i aprovizionat cu tot ce trebuie s intre n tort: ou, zahr, vanilie etc. n aceast analogie, savantul este procesorul (CPU=Central Processing Unit), reeta este rogramul ( ex. un algoritm exprimat ntr-o notaie potrivit), ingredientele sunt datele de intrare. Procesul este activitatea savantului de a citi reeta, de a introduce ingredientele , de a coace tortul. S ne nchipuim acum c fiul savantului vine plngnd c l-a tortului nregistrnd repede unde a nepat ajuns o n albin. reet Savantul (starea ntrerupe coacerea procesului curent este

salvat), caut o carte de prim ajutor (trece la un proces prioritar cu alt program), i aplic instruciunile gsite n ea. Cnd primul ajutor a fost dat, savantul se ntoarce la coacerea tortului i o continu de unde a ntrerupt-o. Ideea este c un proces este o activitate de un anumit fel, cu un program, intrare, ieire, stare etc. Este posibil ca un singur procesor s fie mprit la mai multe procese, cu ajutorul unui algoritm care s determine cnd s fie oprit procesul curent i s fie derulat altul.Un proces este instana de execuie a unui cod. Se utilizeaz i denumirea englez de task (sarcin).Spaiul de adres a unui proces cuprinde: segmentul de cod care conine imaginea executabil a programului i este de tip RO (Read Only) i partajat de mai multe procese; segmentul de date care conine date alocate dinamic sau static de ctre proces; nu este partajat i nici accesibil altor procese; const din: zona de date zona de rezervri (date neiniializate) zona de alocare dinamic;

segmentul de stiv care nu este partajat i crete antrenat n momentul cantitii de memorie pe care o are la dispoziie.

epuizrii

Threadul, numit i fir de execuie, este o subunitate a procesului, utilizat n unele SO. Starea procesului4

ntr-un sistem de calcul, un proces poate fi n diferite stri: pregtit, rulare, blocat, terminat. Cnd procesul este introdus n calculator, este n SISTEM (de obicei fiier sau un grup de fiiere pe un disc). Apoi planificatorul pe termen lung l ia i-l introduce n coada de ateptare READY i atunci procesul este PREGTIT. Planificatorul pe termen scurt UC, conform unui algoritm de planificare ,l introduce n UC. Procesul este n RULARE. De aici, exist trei posibiliti: procesul s-a sfrit i, dup rularea n UC, trece n starea TERMINAT; dac algoritmul folosit este preemptiv (de exemplu time-sharing , cu timp partajat), dac dup o cuant de timp el mai are de rulat, este trecut din nou n coada de ateptare READY n starea PREGTIT; dac n timpul rulrii are nevoie de o resurs extern (de obicei I/O), procesul este trecut n starea BLOCAT. Dup ce i s-a alocat resursa, trece din nou n starea PREGTIT.

Figura. 1.1. Diagrama strilor unui proces. Dac un proces este blocat temporar, el va trebui repornit mai trziu din exact aceeai stare n care se gsea cnd a fost oprit. n acest scop, toate informaiile despre proces trebuiesc salvate. Unui proces i se asociaz de obicei o structur numit BCP (Bloc Control Proces), un descriptor de proces.n mod frecvent, descriptorii nlnuii BLOCAT etc. tuturor proceselor aflate n aceeai stare sunt n cte o list. Vom avea o list de procese n starea PREGTIT, una n starea

5

Figura 1.2. Structura BCP a unui proces.

1.2. Comutarea proceselor Tranziia ntre dou procese active ntr-un SO multitasking se numete comutarea proceselor (proces switch) i are loc ca rspuns la un eveniment din sistem. Comutarea proceselor implic un cost (overhead) important datorit frecvenei cu care are loc n sistem i poate influena performanele acestuia. Eficiena operaiei de comutare a proceselor poate fi crescut prin prevederea unor faciliti hard (seturi de registre multiple) sau printr-o modalitate de structurare a procesului (thread). Un thread (fir de execuie) este o subunitate a procesului, o diviziunea a sa. Fiecare thread reprezint un flux separat de execuie i este caracterizat prin propria sa stiv i prin stri hard (registre, flaguri).Scopul de principal le al crerii threadului este reducerea costului de comutare a threadurile care aparin aceluiai proceselor. De vreme ce toate celelalte resurse, cu excepia procesorului, sunt gestionate procesul care nglobeaz, comutarea ntre proces implic doar salvarea strii hard i restaurarea stivei. Bineneles, comutarea ntre threadurile care aparin unor procese diferite implic acelai cost de comutare. Threadurile sunt un mecanism eficient de exploatare a concurenei programelor. Un program poate fi mprit n mai multe pri.

6

. Figura 1.2.1. Schema de comutare a proceselor Crearea i terminarea proceselor n marea majoritate a sistemelor de operare un proces poate fi creat, n mod dinamic, de ctre alt proces. De obicei un proces printe creeaz un proces fiu. n aceast modalitate de creare, exist mai multe posibiliti n dualitatea printe-fiu: cele dou procese execut, n mod independent, nesincronizat, acelai cod, avnd aceeai stiv i acelai segment de date; fiul execut alt segment de cod dect cel al printelui, nesincronizat; printele i fiul i sincronizeaz activitatea n sensul ei ori se execut nti printele i apoi fiul sau invers. 1.3. Procese n UNIX n sistemul de operare UNIX fiecare proces are un identificator numeric, numit identificator de proces PID. Acest identificator este folosit atunci cnd se face referire la procesul respectiv acestuia: getpid(void) pentru procesul curent;7

din

interiorul

programelor

sau

prin

intermediul interpretorului de

comenzi. Dou apeluri simple permit aflarea PID-ului procesului curent i al printelui

getppid(void) pentru procesul printe. Creerea unui proces se face prin apelul sistem: fork() Prin aceast funcie sistem, procesul apelant, numit printe, creeaz un nou proces, numit fiu, care va fi o copie fidel a printelui. Procesul fiu va avea: propria lui zon de date, propria lui stiv, propriul su cod executabil,toate fiind copiate de la printe, n cele mai mici detalii. O modalitate de utilizare a apelului rularea proceselor i programelor paralele. fork() este de a mpri codul unui proces n dou sau

mai multe procese care se vor executa n paralel. Acest lucru este utilizat n proiectarea i

Exemplul 2 Se d urmtoarea secven de program: fork();printf(A\n);8

fork();printf(B\n); fork();printf(C\n); Presupunnd c toate apelurile funciei fork() se execut cu succes, se cere: -Cte procese sunt create ? -S se traseze arborele printe - fiu al proceselor create. -Cte linii de text vor fi afiate la ieirea standard ? -Este posibil ca linia cu textul B s fie afiat naintea liniei cu textul A ? Sunt create 7 procese, ctelea plus procesul iniial, vor fi 8 procese. Cifrele arat dup al fork() au fost create.

Dup primul fork()se creeaz procesul cu cifra 1. Se va scrie A att n procesul iniial ct i n cel final. Dup al doilea fork(), se creeaz procesul fiu notat cu cifra 2, adic fiecare proces creat pn acum va avea cte un fiu, notat cu 2. Dup al treilea fork(), fiecare proces creat pn acum va crea cte un nou fiu, notat cu 3. n general dup n fork() ,se produc 2n-1 fii.

Figura 1.3.1 Structura arborescent a proceselor. Fiecare proces afieaz liniile de text care urmeaz momentului crerii sale: linia care scrie A este afiat de 21 ori; linia care scrie B este afiat de 22 ori; linia care scrie C este afiat de 23 ori. Numrul total de linii afiate este 21+22+23=14 n ceea ce privete ordinea de afiare a celor 14 linii, intervine nedeterminarea provenit din faptul c nu se tie cine va fi executat primul, printele sau noul fiu creat.

9

Valoarea returnat de fork() este:

-1,

eroare, operaia nu s-a putut executa;0,

n codul

fiului; pidf, n codul printelui, unde pidf este identificatorul de

proces al fiului nou creat.

Pn acum am vzut c prin simplul apel al funciei fork() se creeaz un proces identic cu procesul printe. Pentru a crea un nou proces care s ruleze un program diferit de cel al printelui, se vor folosi funciile execll(), execvl(). Toate aceste funcii primesc ca parametru un nume de fiier care reprezint un program executabil i recicleaz lansarea n execuie a programului. Programul va fi lansat astfel nct se va suprascrie codul, datele i stiva procesului care apeleaz exec(), aa ca, imediat dup acest apel, programul iniial s nu mai existe n memorie. Procesul va rmne, ns, identificat prin acelai PID i va moteni toate eventualele redirectri fcute n prealabil asupra descriptorilor de fiier. n concluzie, lansarea ntr-un proces separat a unui program se face apelnd fork()pentru crearea noului proces, dup care, n poriunea de cod executat de fiu, se va apela una din funciile exec(). n UNIX un proces se poate termina n mod normal sau anormal. Terminarea normal poate fi realizat prin: revenire natural; apelul sistem de tip exit(). Terminarea anormal se produce cnd: se apeleaz abort(); procesul primete un semnal. n marea majoritate a versiunilor UNIX, exist dou apeluri de terminare normal: exit(), _exit().Principalul rol al apelului exit() este s asigure la terminarea procesului tratarea corespunztoare a operaiilor de introducere /extragere , golirea tampoanelor utilizate pentru acest proces i nchiderea tuturor fiierelor deschise. _exit() produce direct revenirea n nucleu, fr operaiile de la funcia exit(). Din cele prezentate pn acum, nu se poate spune nimic despre sincronizarea printe-fiu, adic despre cine termin primul sau cine se execut primul. Apelurile wait() i waitpid() vin n ntmpinarea acestui neajuns. wait() este folosit pentru ateptarea de ctre printe a fiului, deci se execut mai nti fiul i apoi printele. waitpid() este folosit pentru ateptarea unui proces oarecare. n UNIX procesele au un caracter dinamic. Ele se nasc, evolueaz n sistem putnd da natere altor sisteme, i dispar. n felul acesta se creeaz o ierarhie dinamic de procese n sistem, care ncepe cu procesul 0 (swapper), continu cu10

de tipul

exec(), execl(), execlp(),

execv(),

execvp(),

procesul 1 (init), proces ce d natere unor procese fiu. Procesul cu identificatorul 2, proces sistem, apare la unele implementri sub denumirea de pagedaemon i este responsabil de suportul pentru memorie virtual. kill(opiuni)(pid). n general, n execuia printe fiu, exist dou situaii: a) fiul se termin naintea printelui;b) printele se termin naintea fiului.

Terminarea forat a execuiei

unui proces se realizeaz cu comanda

n primul caz, ntre momentul n care se termin fiul i momentul n care el este distrus, procesul fiu este n starea zombie. De obicei, dup terminarea execuiei fiului, printele execut un wait() i scoate fiul din starea zombie. n al doilea caz, n momentul terminrii printelui, nucleul SO este acela care examineaz dac printele a avut copii. Dac da, printele nou al acestor fii va fi procesul init(), nelsnd fiii n starea zombie. Revenind la strile unui proces, sistemul de operare UNIX distruge urmtoarele stri de baz: execuie n mod utilizator (USER); execuie n mod nucleu (KERNEL); gata de execuie (READY); n ateptare (BLOCAT) zombie. Regiuni critice Regiune critic (critical region) sau seciune critica (critical section) reprezint o parte din program care acceseaz o resurs partajat (structur de date sau dispozitiv). Excluderea mutual (mutual exclusion) implic mpiedicarea folosirii simultane de ctre mai multe procese a unei resurse partajate. Dac am putea face ca oricare dou procese ce partajaz anumite resurse s nu fie niciodat n acelai timp n regiunile lor critice, am putea evita cursele. Dei aceast cerin evit condiiile de curs, ea nu este suficient pentru ca procesele paralele s coopereze corect i eficient folosind datele partajate. Pentru a avea o soluie buna, trebuie ndeplinite urmtoarele patru condiii: 1. Oricare dou procese nu se pot afla simultan n regiunile lor critice.11

2. Nici un fel de presupunere nu se poate face asupra vitezelor sau numrului de procesoare. 3. Nici un proces care ruleaz n afara regiunii sale critice nu poate bloca alt proces s intre n regiunea sa critic. 4. Nici un proces nu trebuie s astepte la infinit pentru a intra n regiunea sa critic. Dezactivarea ntreruperilor Metoda: procesul dezactiveaz ntreruperile imediat ce a intrat n regiunea critic i le reactiveaz imediat nainte de a iei din ea. Astfel, pe parcursul regiunii critice procesul nu mai poate fi ntrerupt de nucleu, pentru a comuta procesorul la alt proces (comutarea ntre procese este rezultatul ntreruperilor de ceas sau de alt tip, iar acestea sunt dezactivate) -deci nici un alt proces nu l mai poate incomoda. Avantaje/dezavantaje: o nu este bine s dai proceselor utilizator puterea de a dezactiva ntreruperile; dac nu le mai reactiveaza ? o dac sistemul are mai multe procesoare, dezactivarea ntreruperilor afecteaz doar procesorul care a executat instruciunea de dezactivare; o celelalte procesoare vor rula n continuare procese, care ar putea accesa resursele partajate; o pentru nucleul SO este convenabil s dezactiveze ntreruperile ct timp execut cteva instruciuni de actualizare a unor variabile sau liste; o dac de exemplu, ar aprea o ntrerupere ct timp lista proceselor gata de execuie este ntr-o stare inconsistent, ar putea aprea condiii de curs. Variabile zvor Metoda: se folosete o variabil partajat (zvor) avnd valoarea iniial 0; cnd un proces vrea s intre n regiunea critic, verific zvorul; dac este 0, l face 1, intra n regiunea critic, iar la sfrsit l face 0; dac este deja 1, ateapt s devin 0. Deci zvor = 0, nseamn c nici un proces nu este n regiunea critic i zvor =1 nseamn c exista un proces aflat n regiunea critic. Alternarea strict Metoda: se folosete o variabil partajat care reine al cui este rndul, iar fiecare proces naintea regiunii critice ateapt s aib valoarea potrivit, intr n regiunea critic, iar la ieire i schimb valoarea pentru a-i da voie procesului cellalt. Astfel, metoda nu este util cnd unul dintre procese este mult mai lent dect cellalt.12

De asemenea, metoda impune proceselor s alterneze strict efectuarea regiunilor critice; aceasta poate cauza limitri - de exemplu, n exemplul anterior cu printarea fiierelor, alternarea strict ar mpiedica un proces s nregistreze consecutiv dou fiiere la printare. Verificarea n continuu a unei variabile pn cnd are o anumit valoare se numete ateptare ocupat (busy waiting); ea trebuie n general evitat, deoarece irosete timp pe procesor; este util doar cnd probabilitatea ca ateptarea s fie scurt este rezonabil. Un zvor care foloeste ateptarea ocupat se numete spin lock. 2. PROBLEME CLASICE DE COORDONARE i SINCRONIZARE A PROCESELOR Exist o serie de exemple clasice de coordonare i sincronizare a proceselor n care se regsesc principalele probleme ce apar n astfel de situaii. Multe din aceste probleme se afl n structura oricrui sistem se operare. Totodat aceste probleme clasice se regsesc i n programarea concurent. Le vom aborda ncercnd s le soluionm cu mijloacele specifice prezentate anterior.

2.1. Cina filozofilor (The Dining philosophers problem) Problema poate fi formulat astfel : Se consider cinci filozofi care stau la o mas rotund, fiecare avnd n fa o farfurie cu mncare. ntre dou farfurii vecine exist o singur furculi.Viaa unui filozof const n alternarea perioadelor cnd acesta mnnc i respectiv gndete. Pentru a mnca, un filozof are nevoie de dou furculie. Cnd unui filozof i se face foame, el ncearc s ia furculia din dreapta i furculia din stnga. Dac reuete, mnnc o perioad apoi pune furculiele jos i continu s gndeasc. Soluia evident duce din pcate la eec : #define N 5 /* numrul filozofilor */ void filozof(int i){ while(true){ gndete(); /* filozoful gndete */ /* ia furculia din dreapta */ ia_furculia(i);/* ia furculia din stnga */ ia_furculia((i+1)%N); mnnc(); /* mnnc */ /* pune furculia din stnga pe mas */ /* pune furculia din dreapta pe mas */ pune_furculia(i); } }13

/* i=nr. filozof

0 i 4 */

pune_furculia((i+1)%N);

S presupunem c toi cei cinci filozofi iau fiecare furculia din stnga simultan. Niciunul nu va mai putea s ia furculia din dreapta, rezultnd o situaie de impas. Programul poate fi modificat n sensul c, dup ce ia furculia din stnga, filozoful i verific dac furculia din dreapta este disponibil. Dac nu, pune furculia din stnga pe mas, ateapt un timp i apoi repet ntregul proces. Cu un pic de ghinion, toi filozofii pot ncepe algoritmul simultan, s ia furculiele din stnga, s observe c furculiele din dreapta nu sunt disponibile, s pun pe mas furculiele din stnga, s atepte, s ia din nou furculiele din stnga simultan .a.m.d., pentru totdeauna. O observaie care poate veni n minte este ca filozofii s atepte un timp aleator nainte de a relua procesul de achiziionare a furculielor. Aceast observaie este bun, dar se prefer soluiile care merg ntotdeauna i nu eueaz din cauza unei anumite serii de numere aleatoare. O mbuntire ar fi folosirea unui semafor. Astfel, nainte s ia furculiele, filozoful i poate apela funcia DOWN pe un semafor mutex. Dup ce mnnc i pune furculiele pe mas, apeleaz funcia UP pe mutex. Din punct de vedere teoretic, soluia este bun, dar practic, duce la un rezultat puin curios : la un moment dat, doar un singur filozof poate mnca dei sunt disponibile cinci furculie i deci, pot mnca doi filozofi simultan.

2.2. Problema cititorilor i scriitorilor Considerm o baz de date (de ex., pentru rezervarea biletelor la avion) i multe procese care vor s acceseze aceast baz de date pentru scriere sau citire. Se permite ca mai multe procese s citeasc simultan dar, dac unul din procese vrea s scrie (s modifice) baza de date, niciunul din celelalte procese nu are voie s acceseze baza de date (nici pentru scriere, nici pentru citire).O soluie este prezentat mai jos. Primul cititor care acceseaz baza de date, execut un DOWN pe un semafor db (nepermind niciunui scriitor s acceseze baza de date). Urmtorii cititori incrementeaz un contor rc. Pe msur ce cititorii pleac, contorul este decrementat, iar ultimul execut un UP pe semaforul db, permind astfel scriitorului blocat, dac exist, s acceseze baza de date. Aceast soluie acord prioritate cititorilor asupra scriitorilor. Astfel, dac un scriitor apare n timp ce ali cititori se afl deja n baza de date, scriitorul trebuie s atepte pn pleac toi cititorii. typedef int semafor; semafor mutex=1; semafor db=1; int rc=0; /* controleaz accesul la rc */14

/* controleaz accesul la baza de date */ /* nr. procese cititor */ void cititor(void){ while(1){ /* ciclu infinit */ down(mutex); /* acces exclusiv al variabilei rc */ if(++rc==1) down(db); /* dac este primul cititor => nici un alt scriitor nu mai*/ /* poate accesa baza de date */ up(mutex); /* iese din regiunea critic */ citete_baza_de_date(); /* acceseaz baza de date */ down(mutex); /* acces exclusiv al variabilei rc */ if(--rc==0) up(db); /* dac este ultimul cititor => se permite accesul scriitorilor */ up(mutex); /* iese din regiunea critic */ } } void scriitor(){ while(1){ /* ciclu infinit */ down(db); /* acces exclusiv la baza de date */ scrie_n_baza_de_date(); /* modific baza de date */ up(db); /* permite altor procese s acceseze baza de date */ } } 2.3. Problema brbierului somnoros Prvlia unui brbier este format din dou camere, una la strad, ateptare, i una n spate,

folosit ca sal de

n care se gsete scaunul pe care se aeaz clienii pentru a fi

servii. Dac nu are clieni, brbierul somnoros se culc. S se simuleze activitile care se desfoar n prvlia brbierului. Rezolvare: Aceast problem este o reformulare a problemei productor/consumator, n care locul bufferului de obiecte este luat de scaunul brbierului iar consumatorul este brbierul care i servete (consum) clienii. n sala de ateptare sunt n scaune pe care se aeaz clienii; fiecare scaun este pentru un client. Dac nu sunt clieni, brbierul doarme n scaunul de frizerie. Cnd vine primul client l trezete pe brbier i brbierul l servete pe client, aezndu-l n scaunul de frizerie. Dac n acest timp sosesc i ali clieni, ei vor atepta pe cele n scaune. Cnd toate scaunele sunt ocupate i mai vine nc un client, acesta prsete prvlia. Problema const n a programa aceste activiti n aa fel nct s nu se ajung la aa numitele condiii de curs. Este o problem clasic cu multe aplicaii, mai ales n cele de help desk. Pentru implementarea soluiei vom utiliza dou semafoare i un mutex:15

clieni un semafor ce contorizeaz clienii ce ateapt; brbier un semafor care arat dac brbierul este ocupat sau nu; el are dou valori, 0 dac brbierul este ocupat i 1 dac este liber; mutexc un mutex folosit pentru excludere mutual; arat dac scaunul de frizerie este ocupat sau nu. De asemenea mai folosim o variabil: Clieni n ateptare care, aa cum arat i numele, numr clienii care ateapt. Aceast variabil trebuie introdus deoarece nu exist o cale de a citi valoarea curent a semafoarelor i de aceea un client care intr n prvlie trebuie s numere clienii care ateapt. Dac sunt mai puini dect scaunele, se aeaz i el i ateapt; dac nu, prsete frizeria. S descriem algoritmul . Cnd brbierul intr dimineaa n prvlie, el execut funcia brbier(), blocnd semaforul clieni care este iniial pe zero. Apoi se culc i doarme pn vine primul client. Cnd acesta sosete, el execut funcia clieni() i ocup mutexul care arat c scaunul de frizerie este ocupat. Dac intr un alt client n acest timp, el nu va putea fi servit deoarece mutexul este ocupat. Va numra clienii care ateapt i, dac numrul lor e mai mic dect numrul scaunelor, va rmne, dac nu, va prsi prvlia. Rmnnd, va incrementa variabila clieni n ateptare. Cnd clientul care este servit a fost brbierit, el elibereaz mutexul, trezind clienii care ateapt i unul din ei va ocupa mutexul, fiind servit la rndul su. Iat mai jos implementarea acestui algoritm. #define scaune 20 /*se definete numrul type def int semafor; type def int mutex ; semafor clienti=0; /*declaraii i semafor brbier=0; mutexc=1; int clientiinasteptare=0; void brbier() {while(1){ wait(clienti); wait(mutexc); clientiinasteptare--; signal(brbier); signal(mutexc); tunde();}void clienti() {wait(mutexc); if(clientiinasteptare