Sunteți pe pagina 1din 7

Lucrarea 4

Mecanisme de Sincronizare n Linux


Fie urmtorul program:
int i = 0;
void *fir(void* arg){
i++;
}
int main(){
pthread_t th[3];
int j;
for(j = 0; j < 3; j++){
int ret = pthread_create(th[j]! "#$$! fir! "#$$);
if(ret){
printf(%eroare&n%);
e'it(());
}
}
for(j = 0; j < 3; j++){
pthread_join(th[j]! "#$$);
}
printf(%*a+oarea +,i i e-te .d&n%! i);
}
Programul este foarte simplu: firul principal trei fire de execuie care incrementeaz o
variabil global i, iniializat cu 0. La final, dup ce ateapt terminarea celor trei fire,
firul principal afieaz valoarea lui i. i aici apare problema, deoarece programul nu este
determinist, valorile posibile afiate fiind: !, " sau #.
!

$cest lucru se datoreaz faptului c instruciunea de incrementare nu se execut atomic.
%a const de fapt din urmtoarea secven de operaii atomice:
mov eax,&i'
add eax,!
mov &i',eax
(aloarea ! se obine dac ultimul fir care salveaz valoarea lui i a )ncrcat valoarea 0. *n
scenariu posibil este:
!
+ei, din motive pe care o s le )nelegei mai bine dup parcurgerea capitolului despre planificarea
proceselor, valorile ! i " sunt greu de obinut folosind un singur procesor. +ar dac firele care modific
valoarea variabilei i ar fi mai ,consistente, probabilitatea de a obine valori distincte ar crete.
Fir !
mov eax,&i'
add eax,!
mov &i',eax
Fir "
mov eax,&i'
add eax,!
mov &i',eax
Fir #
mov eax,&i'
add eax,!
mov &i',eax
(aloarea " se poate obine cu urmtorul scenariu:
Fir !
mov eax,&i'
add eax,!
mov &i',eax
Fir "
mov eax,&i'
add eax,!
mov &i',eax
Fir #
mov eax,&i'
add eax,!
mov &i',eax
Pe c-nd valoarea # nu se poate obine numai cu un scenariu )n care toate cele trei
instruciuni se execut atomic:
Fir !
mov eax,&i'
add eax,!
mov &i',eax
Fir "
mov eax,&i'
add eax,!
mov &i',eax
Fir #
mov eax,&i'
add eax,!
mov &i',eax
+e fapt cele trei instruciuni definesc o zon critic, )n care nu poate fi activ dec-t un
singur proces )n orice moment. *nul din mecanismele implementate )n Linux care ne
permite definirea unei zone critice este mutex.ul.
Mutex
*n mutex este dispozitiv care nu poate avea dec-t dou stri: blocat de un singur fir de
execuie sau neblocat de nici un fir de execuie.
*n mutex poate fi iniializat folosind apelul:
int pt/read0mutex0init1pt/read0mutex0t 2mutex,
const pt/read0mutexattr0t 2mutexattr34
$cest apel iniializeaz obiectul de la locaia memorat )n mutex conform atributelor
specificate cu a5utorul celui de.al doilea argument
"
. Linux6/reads nu suport dec-t un
singur atribut, mutex_kind. *n mutex poate fi : fast 1implicit3, recursive sau error
c/ec7ing. *n mutex mai poate fi iniializat folosind # constante:
pt/read0mutex0t fastmutex 8 P69:%$+0;*6%<0=>=6=$L=?%:4
pt/read0mutex0t recmutex 8
P69:%$+0:%@*:A=(%0;*6%<0=>=6=$L=?%:0>P4
pt/read0mutex0t errc/7mutex 8
P69:%$+0%::B:@9%@C0;*6%<0=>=6=$L=?%:0>P4
$pelul )ntoarce )ntotdeauna 0.
Pentru a bloca un mutex avem dou variante:
int pt/read0mutex0loc71pt/read0mutex0t 2mutex34
int pt/read0mutex0trDloc71pt/read0mutex0t 2mutex34
Primul apel bloc/eaz mutex.ul specificat de parametru. +ac mutexul era neblocat ele
devine blocat de firul apelant i funcia )ntoarce imediat. +ac mutexul era blocat de un
alt fir, firul apelant este suspendat p-n c-nd este acesta este deblocat.
+ac )ns mutexul era de5a blocat c/iar de firul apelant, comportamentul apelului
depinde de tipul mutexului:
fast . firul apelant este suspendat p-n c-nd mutexul va fi deblocat, ceea ce
poate fi o mare problem.
recursive E apelul reuete, mutexul fiind blocat )nc o dat, el trebuind
,deblocat, de tot at-tea ori de c-te ori a fost blocat pentru a putea fi blocat i de
un alt fir.
"
+ac al doilea argument este >*LL se folosesc atributele implicite.
error c/ec7ing E apelul )ntoarce imediat cu eroarea %+%$+LC.
@el de.al doilea apel, pthread_mutex_trylock, se comport aproape identic cu primul,
singura diferen const-nd )n aceea c nu suspend niciodat firul apelant, )ntorc-nd
imediat codul de eroare %F*AG.
+up ce blocai un mutex, )n general este bine s.l i deblocai, c-ndva. Pentru aceasta
putei folosi numai:
int pt/read0mutex0unloc71pt/read0mutex0t 2mutex34
Hn principiu se presupune c firul care )ncearc s debloc/eze mutexul este cel care l.a
blocat. +ar i aici, comportamentul apelului depinde de tipul mutexului:
fast E )l debloc/eaz )ntotdeauna, indiferent de cine )l blocase anterior.
recursive E se decrementeaz numrul de blocri i doar atunci c-nd acest numr
a5unge 0 este mutexul considerat liber.
error c/ec7ing E numai )n acest caz se verific nu numai c mutexul era blocat,
dar i dac era blocat c/iar de firul care dorea s.l debloc/eze. +ac nu e aa, se
)ntoarce un cod de eroare ls-nd mutexul neatins.
@omportamentul )n cazul fast i recursive nu este portabil.
+ac nu mai avei nevoie de mutex, )l putei distruge:
int pt/read0mutex0destroD1pt/read0mutex0t 2mutex34
Hn principiu, dac mutexul era neblocat, resursele acestuia sunt eliberate, dar cum )n
Linux un mutex nu are nici o resurs asociat, apelul nu face dec-t s verifice dac
mutexul era liber.
Hn caz de succes, apelurile de mai sus )ntorc 0.
$cum putem prote5a incrementarea variabilei i:
int i = 0;
pthread_m,te'_t m,t, = /012345_6#037_8"8084$8932;
void *fir(void* arg){
pthread_m,te'_+oc:(m,t,);
i++;
pthread_m,te'_,n+oc:(m,t,);
}
int main(){
pthread_t th[3];
int j;
for(j = 0; j < 3; j++){
int ret = pthread_create(th[j]! "#$$! fir! "#$$);
if(ret){
printf(%eroare&n%);
e'it(());
}
}
for(j = 0; j < 3; j++){
pthread_join(th[j]! "#$$);
}
printf(%*a+oarea +,i i e-te .d&n%! i);
}
Semafoare
3
+ei toat lumea tie ce sunt acelea semafoare o s )ncercm s le predefinim.
Aemaforul este un contor asupra cruia nu se pot efectua dec-t dou operaii atomice:
incrementare.
ateptare ca semaforul s devin mai mare ca 0 i apoi decrementare.
*n semafor este iniializat cu a5utorul apelului:
Iinclude Jsemap/ore./K
int sem0init1sem0t 2sem, int ps/ared, unsigned int value34
(aloarea contorului este iniializat de cel de.al treilea argument. @el de.al doilea
argument specific dac semaforul este local procesului curent 1ps/ared este 03 sau este
parta5at de mai multe procese 1ps/ared este diferit de 03. +eocamdat acest argument
trebuie s fie 0 deoarece Linux6/reads nu suport semafoare parta5ate de mai multe
procese. Primul argument este un pointer la semaforul care trebuie iniializat.
Pentru a decrementa semaforul avem dou variante:
int sem0Lait1sem0t 2 sem34
int sem0trDLait1sem0t 2 sem34
+ac semaforul este 0, sem_wait bloc/eaz firul apelant p-n c-nd semaforul devine mai
mare dec-t 0, dup care )l decrementeaz printr.o operaie atomic. $ltfel, semaforul este
decrementat i apelul )ntoarce imediat, lucru care se )nt-mpl i )n cazul apelului
sem_trywait. +iferena apare atunci c-nd semaforul este 0, sem_trywait )ntorc-nd imediat
eroarea %$M$=>
N
, ls-nd semaforul neatins.
Hn caz de succes, ambele )ntorc 0.
Pentru a incrementa semaforul exist apelul:
int sem0post1sem0t 2 sem34
$ceast funcie nu bloc/eaz niciodat firul apelant, )ntorc-nd 0 )n caz de succes.
#
Hn aceast seciune sunt descrise semafoarele PBA=< !00#.!b.
N
set-nd errno
Bcazional, este nevoie s aflai ce valoare are contorul unui semafor:
int sem0getvalue1sem0t 2 sem, int 2 sval34
$ceast valoare este memorat )n adresa spre care indic parametrul sval.
Hn ceea ce privete urmtorul apel,
int sem0destroD1sem0t 2 sem34
comportamentul su este similar cu cel care distruge un mutex.
Condiii
@ondiiile sunt mecanisme de sincronizare similare cu apelurile sleep i La7eup descrise
la curs, av-nd )ns protecii )mpotriva problemelor acestora prin asocierea cu un mutex.
B s )ncep cu iniializarea:
pt/read0cond0t cond 8 P69:%$+0@B>+0=>=6=$L=?%:4
int pt/read0cond0init1pt/read0cond0t 2cond,
pt/read0condattr0t 2cond0attr34
+eoarece Linux6/reads nu suport atribute pentru condiii nu sunt multe de spus despre
iniializareO dec-t c face iniializarea.
Pentru a semnaliza un fir care ateapt o variabil condiie se folosete:
int pt/read0cond0signal1pt/read0cond0t 2cond34
+ac mai multe fire sunt suspendate )n ateptarea condiiei numai unul dintre ele este
repornit, dar nu se specific care. +ac dorii s repornii toate firele, atunci vor fi
semnalizate toate:
int pt/read0cond0broadcast1pt/read0cond0t 2cond34
Pentru a atepta dup o condiie:
int pt/read0cond0Lait1pt/read0cond0t 2cond,
pt/read0mutex0t 2mutex34
$cest apel debloc/eaz mutexul i ateapt pentru ca variabila condiie s fie
semnalizat, totul )ntr.o operaie atomic. ;utexul trebuie s fie blocat de firul apelant )n
momentul apelului. Hn momentul )n care firul este repornit, mai )nt-i acesta ateapt s
rebloc/eze mutexul.
+ac nu dorii ca firul s fie suspendat la nesf-rit putei pune o limit de timp pentru
ateptare:
int pt/read0cond0timedLait1pt/read0cond0t 2cond,
pt/read0mutex0t 2mutex,
const struct timespec 2abstime34
+ac se atinge limita de timp fr ca nimeni s semnalizeze condiia, apelul )ntoarce
eroarea %6=;%+B*6 i mutexul este reblocat. Parametrul abstime specific un timp
absolut, cu aceeai origine cu time i gettimeofdaD: lui 0 )i corespunde 00:00:00 M;6,
ianuarie !, !PQ0.
Probleme Propuse.
!. A se determine dac un element apare )ntr.un vector oarecare, folosind n
procesoare.
". A se determine pe ce poziii apare un element )ntr.un vector oarecare, folosind n
procesoare.
#. B resurs poate fi utilizat de dou tipuri de procese: albe i negre. $tunci c-nd
resursa este folosit de procese albe ea nu mai poate fi folosit de procese negre.
%ste valabil i reciproca. A se implementeze accesul la resurs, evit-ndu.se
)nfometarea.
N. A se sorteze elementele unui vector cu n procesoare.
R. A se genereze toate numerele prime mai mici dec-t o anumit valoare, folosind n
procesoare.
S. A se coordoneze semafoarele de la captul unui tunel cu o singur band,
folosindu.se de senzorii de la fiecare capete care semnalizeaz intrarea i ieirea
mainilor, astfel )nc-t s nu se permit intrarea pe la un capt c-t timp mai sunt
maini )n tunel merg-nd )n sens invers. ;ainile s fie simulate cu a5utorul firelor
de execuie.

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