Sunteți pe pagina 1din 25

PROGRAMAREA APLICA|IILOR {N TIMP REAL

Curs 3 PATR Sincronizarea - Semafoare binare - Semafoare generalizate -

Sincronizarea taskurilor - definitie:

Sincronizarea = abilitatea mai multor taskuri de a-si coordona activitatile prin interschimbarea informatiei

doua taskuri, Ti si Tj Pi, respectiv Pj, definesc punctul de sincronizare

mecanisme pentru realizarea sincronizarii: semafoarele (binare, generalizate), mutex-uri (caz particular de semafor binar) monitoare transmiterea de mesaje

caz particular: sincronizarea prin planificare pe conditie de timp

Mecanisme pentru realizarea sincronizarii - semafoare:

pentru a transmite un semnal prin intermediul semaforului s, taskul executa o primitiva signal(s) pentru a receptiona un semnal prin intermediul semaforului s, taskul executa primitiva wait(s) notatii (Dijkstra) pentru wait se foloseste notatia P proberen (to test) / passeren (to pass)

pentru signal se foloseste notatia V verhogen (to increment) / vrygeven (to release)

Mecanisme pentru realizarea sincronizarii - semafoare:

un semafor s = variabila de tip intreg asupra careia se executa cele doua primitive, P si V, astfel:

primitiva P (operatia de tip wait) decrementeaza valoarea semaforului

daca valoarea semaforului devine < 0, taskul care a executat P(s) se blocheaza

primitiva V (operatia de tip signal) incrementeaza valoarea semaforului

daca valoarea este > 0, este deblocat procesul care s-a blocat in P(s)

Pe un semafor pot fi executate doar aceste trei operatii, adica: initializare (cu o valoare > 0) primitiva P, P(s) primitiva V, V(s)

Mecanisme pentru realizarea sincronizarii - semafoare:

primitivele P si V sunt atomice nu pot si intrerupte, fiecare rutina este tratata ca un pas indivizibil sunt de tip test-and-set primitiva P intr-un singur pas: testeaza, decrementeaza si trece daca valoarea semaforului ramane > 0 Semafor liber daca valoarea > 0 primitiva V intr-un singur pas: incrementeaza si deblocheaza taskul care asteapta pe valoare semafor > 0 Semafor ocupat daca valoarea = 0

Semafoare binare:

Notam SB = {valB, q}, unde valB= {0,1} operatia de tip P(SB) are urmatoarele efecte:

daca valoarea SB = 1, atunci task-ul apelant isi continua executia, facand in acelasi timp ca val(SB) = 0; daca initial val(SB) = 0, atunci task-ul apelant este trecut n asteptare (este inserat in q(SB)) si se da controlul planificatorului de task-uri;

operatia de tip V(SB) are urmatoarele efecte:

se face val(SB) = 1. Daca exista task-uri n coada q, unul si numai unul este scos din coada si este trecut n starea gata de executie (READY). Se da controlul planificatorului de task-uri.

Semafoare binare - exemplu:

sa se calculeze valoarea urmatorului polinom de gradul 7: u(X) = u0 + u1X + u2X2 + u3X3 + u4X4 + u5X5 + u6X6 + u7X7

alocarea activitatilor pe taskuri:

definiti punctele de sincronizare cite semafoare? primitivele P si V

Semafoare binare - exemplu:

sa se calculeze valoarea urmatorului polinom de gradul 7: u(X) = u0 + u1X + u2X2 + u3X3 + u4X4 + u5X5 + u6X6 + u7X7

alocarea activitatilor pe taskuri:


Task 2 b1= u5X + u4 Task 3 c1 = u3X + u2 c2 = c1X2 + d1 Task 4 d1= u1X + u0 Task 5 X2

Task 1 a1 = u7X + u6 a2 = a1X2 + b1 a3 = a2X4 + c2


X4

definiti punctele de sincronizare cite semafoare? primitivele P si V

Semafoare binare - exemplu:

Task 1 a1 = u7X + u6 P(S1) P(S2) a2 = a1X2 + b1 P(S5) P(S6) a3 = a2X4 + c2

Task 2 b1= u5X + u4 V(S1)

Task 3 c1 = u3X + u2 P(S3) P(S4) c2 = c1X2 + d1 V(S5)

Task 4 d1= u1X + u0 V(S3)

Task 5 X2 V(S2) V(S4) X4 V(S6)

Sincronizarea taskurilor - semafoare generalizate:

pot fi utilizate pentru a proteja mai multe resurse sau pentru a tine evidenta mai multor resurse semaforul generalizat este initializat cu numarul total de resurse de acelasi fel disponibile in sistem semaforul generalizat este initializat cu o valoare intreaga > 0 specifica acces liber daca valoarea sa este > 0 specifica interdictia accesului daca valoarea sa este 0

Sincronizarea taskurilor - semafoare generalizate:

notatie

SG = (valSB, qSB)

primitiva P(SG) decrementeaza valoarea semaforului valSG <--- valSG - 1

conditia de trecere este valSG > 0

primitiva V(SG) face valSG <--- valSG + 1


necesitatea: o operatie V asupra unui semafor binar cu valoarea 1 nu are nici un efect

Sincronizarea taskurilor - semafoare generalizate (exemplu):

sa se calculeze valoarea urmatorului polinom de gradul 7: u(X) = u0 + u1X + u2X2 + u3X3 + u4X4 + u5X5 + u6X6 + u7X7

alocarea activitatilor pe taskuri:


Task 2 b1= u5X + u4 Task 3 c1 = u3X + u2 c2 = c1X2 + d1 Task 4 d1= u1X + u0 Task 5 X2

Task 1 a1 = u7X + u6 a2 = a1X2 + b1 a3 = a2X4 + c2

X4

Sincronizarea taskurilor - semafoare generalizate (exemplu):

Task 1 a1 = u7X + u6 P(S1) P(S4) a2 = a1X2 + b1 P(S5) P(S6) a3 = a2X4 + c2

Task 2 b1= u5X + u4 V(S1)

Task 3 c1 = u3X + u2 P(S3) P(S4) c2 = c1X2 + d1 V(S5)

Task 4 d1= u1X + u0 V(S3)

Task 5 X2 V(S4) V(S4) X4 V(S6)

Semafoare sub QNX:

QNX - semafoare pentru controlul accesului la resurse administrare unnamed semaphores


#include <semaphore.h> int sem_init( sem_t * sem, int pshared, unsigned value ); int sem_destroy( sem_t * sem ); sem_t * sem_open( const char * sem_name, int oflags, [int sharing, unsigned int val] ); int sem_close( sem_t * sem ); int sem_unlink( const char * sem_name );

utilizare
#include <semaphore.h> int sem_post( sem_t * sem ); int sem_trywait( sem_t * sem ); int sem_wait( sem_t * sem ); int sem_getvalue( sem_t * sem, int * value );

named semaphores

Semafoare sub QNX:


QNX Neutrino are semafoare generalizate (counting semaphores)

atunci cand semaforul este creat (cu sem_open() sau sem_init() call) parametrul val specifica o valoare (count) - 0 inseamna none are available apelul lui sem_wait() verifica daca valoarea count este > 0, decrementeaza count si returns success, altfel apelul blocheaza taskul un sem_post() incrementeaza valoarea count, deblocand taskul care asteapta

Exista doua variante de semafoare:

named semaphores: sunt create cu sem_open(), inchise cu sem_close(), distruse cu sem_unlink() permit proceselor sa acceseze un semafor comun, cunoscut prin nume; este singura comunicatie intre procese unnamed semaphores: create cu sem_init(), si distruse cu sem_destroy() sunt utile intre firele unui proces, structura semaforului (de tip sem_t) trebuie sa fie disponibila in memoria comuna, sau intre procese la care structura semaforului este mapata intr-un obiect de memorie indiferent de tipul semaforului, se aplica functiile sem_post(), sem_trywait(), sem_wait(), si sem_getvalue()

Sincronizare prin intermediul variabilelor de tip eveniment:

in anumite sisteme (nuclee) de operare in timp-real exista evenimente


un tip special de variabile care pot fi utilizate pentru sincronizare sunt asemanatoare semafoarelor binare, pot lua doua valori 1 (liber) si 0 (ocupat) trecerea de punctul de asteptare pe eveniment nu modifica valoarea variabilei de tip eveniment !

operatiile care se pot executa pe o variabila de tip eveniment nu sunt atomice

nu pot fi folosite pentru excludere mutuala !

Sincronizare prin intermediul variabilelor de tip eveniment:

executie ciclica si sincronizare pentru doua taskuri


Task 1 Initializare Task 2 Initializare

actiune_1() set_ev(flag) actiune_4()

clear_ev(flag) actiune_2() wait_set_ev(flag) actiune_3()

Fire de executie:

crearea firelor de executie:

#include <pthread.h> int pthread_create( pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void* ), void* arg );

exemplu: pthread_create (&tid, &attr, &func, &arg);


executia firului incepe in func() func() este main pentru acest fir toti ceilalti parametri pot fi NULL pthread_create() returneaza in parametrul tid identificatorul firului nou creat (thread id) arg contine diverse date ce pot fi transmise catre func() attr permite sa se specifice atribute ale firului, de exemplu prioritatea sa, ...

Fire de executie - atribute:

setarea atributelor firelor de executie pthread_attr_t attr; pthread_attr_init(&attr); ... /* set up the pthread_attr_t structure */ pthread_create (&tid, &attr, &func, &arg);

pthread_attr_init() seteaza membrii pthread_attr_t la valori default

Fire de executie functii pentru manipularea atributelor:

functii pentru setarea atributelor initializare, distrugere pthread_attr_init(), pthread_attr_destroy()

setare

pthread_attr_setdetachstate(), pthread_attr_setinheritsched(), pthread_attr_setschedparam(), pthread_attr_setschedpolicy(), pthread_attr_setstackaddr(), pthread_attr_setstacksize()


In general, se apeleaza pthread_attr_init() pentru a initializa o structura de atribute, dupa care se apeleaza functiile de tipul pthread_attr_set*() pentru a manipula structura de atribute - in continuare vom considera ca pthread_attr_init() este intotdeauna apelata

Fire de executie detectam cand se termina (joining):

asteptam ca firele sa se termina si aflam de ce: daca un fir este joinable, asteptam sa moara (die)
pthread_create (&tid, , worker_thread, ); // at this point, worker_thread is running // ... do stuff // now check if worker_thread died or wait for // it to die if it hasnt already pthread_join (tid, &return_status);

daca moare inainte de apelul lui pthread_join(), atunci pthread_join() face return imediat si return_status va contine valoarea de return a firului sau valoarea transmisa catre pthread_exit() dupa ce s-a executat pthread_join(), informatia despre firul care s-a terminat se pierde

Fire de executie detectam cand se termina (joining):

un thread poate fi facut unjoinable, si se numeste detached

un astfel de thread nu poate fi asteptat sa se termina, si cind se termina, nu mai stim nimic despre el ca sa facem un fir detached in momentul cand il cream spunem:

pthread_attr_init (&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); pthread_create (&tid, &attr, worker_thread, NULL);

Fire de executie operatii asupra firelor de executie:

cateva operatii asupra firelor de executie: terminate the calling thread set signal signo on thread tid make the thread detached (i.e. unjoinable) find out your thread id compare two thread ids

pthread_exit(retval) pthread_kill(tid, signo) pthread_detach(tid) tid = pthread_self() pthread_equal (tid1, tid2)

Fire de executie operatii asupra firelor de executie:

Obs 1: pthread_exit()

daca firul este joinable, valoarea retval este facuta disponibila pentru oricare dintre firele joining the terminating thread, altfel daca firul este detached, toate resursele sistemului alocate are immediately reclaimed si retval este pierduta

Fire de executie - exemplu:

program pentru calculul valorii unui polinom - Polinom.c