Professional Documents
Culture Documents
Curs 4 PATR
Curs 4 PATR
ÎN
TIMP-REAL
Curs 4
#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, ...
amandoua:
struct sched_param param;
pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
param.sched_priority = 15;
pthread_attr_setschedparam (&attr, ¶m);
pthread_attr_setschedpolicy (&attr, SCHED_RR);
pthread_create (NULL, &attr, func, arg);
setam doar prioritatea:
struct sched_param param;
pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
param.sched_priority = 15;
pthread_attr_setschedparam (&attr, ¶m);
pthread_attr_setschedpolicy (&attr, SCHED_NOCHANGE);
pthread_create (NULL, &attr, func, arg);
dupa ce s-a executat pthread_join(), informatia despre firul care s-a terminat se pierde
un astfel de thread nu poate fi asteptat sa se termine, 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);
• 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
sincronizarea taskurilor
aspecte colaterale:
– deadlock
– starvation
Excluderea mutuala = abilitatea mai multor taskuri de a imparti resurse sau date in asa fel
incat un singur proces sa aiba acces la o resursa partajata (engl. shared resource) la un
moment dat
un singur task poate executa sectiunea critica la un moment dat, restul fiind blocate
in fiecare task avem o secventa de instructiuni organizate sub forma unei sectiuni (zona) critice
se aloca un singur semafor binar pentru toate taskurile (problema este globala si simetrica)
o valoare 1 a semaforului binar semnifica faptul ca este permis accesul in zona critica
o valoare 0 a semaforului binar semnifica faptul ca nu este permis accesul în zona critica
in fiecare task, la intrarea si iesirea din sectiunea ctitica avem o secventa de instructiuni de
forma
P(S);
sectiune critica;
V(S);
sa nu existe situatii de blocare (un task care asteapta sa intre în zona sa critica trebuie sa
obtina accesul dupa un timp finit)
toate task-urile care asteapta intrarea în zona critica respectiva trebuie sa obtina accesul la
un moment dat
in consecinta:
zonele critice trebuie sa fie cât mai scurte (este de preferat sa nu contina operatii de I/O)
zonele critice trebuie sa se execute în timp finit
in zona critica a unui task nu se definesc alte zone critice, sincronizari, etc, pentru ca ele
pot conduce foarte usor la blocare
zonele comune de date sunt zone speciale create de sistem pentru comunicatia între task-
uri, sunt vizibile din toate task-urile si sunt gestionate de catre sistemul de operare
in unele sisteme zona comuna de date se numeste memorie partajata (engl. shared
memory), buffer, etc.
accesul la o astfel de zona de date se face prin adresa (pointer)
zona comuna de date este creata de un task printr-un apel de functii sistem
celelalte taskuri "deschid" zona tot prin apeluri de functii sistem
ordinea în care se consuma datele trebuie sa fie identica cu ordinea în care sunt
produse datele
un set de date produse nu trebuie consumat de doua ori
sa se consume toate seturile de date produse (sa nu se piarda date)
Blocat Deblocat
Task inserare în buffer plin inserare item
producator
Task scoate din buffer gol scoate item
consumator
Initializari (global):
task_consumator()
{
// citeste item-ul w din buffer si actualizeaza
// pozitia de citire
w = b[out];
out = (out + 1)%n;
consuma_date();
}
lock()
... sectiune critica
unlock()
exemplu: QNX
• Mutex-ul (engl. mutual exclusion lock) reprezinta cel mai simplu mecanism de sincronizare.
Un mutex este folosit pentru a asigura accesul exclusiv la o zona de date folosita in comun
de mai multe fire de executie. Un mutex se poate afla in doua stari:
incuiat (engl. locked), prin apelul functiei pthread_mutex_lock (se specifica in acest fel
inceputul sectiunii critice);
liber (engl. unlocked), prin apelul functiei pthread_mutex_unlock (specificand sfarsitul
sectiunii critice).
Firele de executie care incearca sa incuie un mutex deja incuiat se vor bloca pana cand
firul de executie va fi deblocat.
Cand firul de executie elibereaza mutexul, se va debloca urmatorul fir de executie (in
ordinea prioritatii) care astepta eliberarea lui, va incuia mutexul si va deveni proprietarul
acestuia.
In acest fel, firele de executie trec prin regiunea critica in ordinea prioritatii
o aplicatie formata din doua fire de executie care incrementeaza un contor (resursa partajata)
int main(void){
pthread_t FIR[2];
int i;
for(i=0; i<2;i++)
if(pthread_create(FIR+i, NULL,(void*)(*(functie+i)),(void*)(r+i))!=0){
perror("pthread_create");
return EXIT_FAILURE;
}
it = *iteratii;
for(i =0; i < it; i++){
pthread_mutex_lock(&mutex);
printf("\nFir1: Setez contorul, la iteratia %d \n", i);
contor++;
pthread_mutex_unlock(&mutex);
sleep(2);
}
}
it = *iteratii;
for(i =0; i < it; i++){
pthread_mutex_lock(&mutex);
printf("Fir2: Setez contorul, la iteratia %d \n", i);
contor++;
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
18-Mar-16 Programarea Aplicatiilor in Timp-Real 29
Alte mecanisme de sincronizare si comunicatie intre procese
procese
mecanisme de comunicatie intre procese – zone comuna de date
– transmitere de mesaje
int state;
thread_1()
{
while(1){
// wait pana cand "state" se modifica
// apoi executa ceva
}
}
se rezolva cu condvars
exemplu: o aplicatie software citeste date si le transmite catre un dispozitiv extern (hardware)
(1) primul fir primeste datele (e.g. de la un proces client), si le pune intr-un buffer si
o variabila conditionala este folosita pentru a bloca un fir de executie in interiorul sectiunii critice,
pana cand este indeplinita o anumita conditie
utilizare:
intr-un fir
pthread_mutex_lock(&m);
...
while (!conditie) {
pthread_cond_wait(&cv, &m);
}
...
pthread_ mutex_unlock(&m);
in alt fir
pthread_cond_signal(&cv);
un singur fir de executie poate examina conditia, deoarece mutex-ul este acaparat inainte de a face testarea
in cazul in care conditia este adevarata, firul se va bloca pana cand un alt fir va executa
pthread_cond_signal() sau pthread_cond_broadcast()
scrie_in_buffer();
pthread_cond_signal(&cond); // notifica
cod pentru firul care citeste datele din buffer si le transmite la dispozitiv
while(1){
pthread_mutex_lock(&mutex);
if(!data_ready)
pthread_cond_wait(&cond, &mutex);
data_ready = 0;
pthread_mutex_unlock(&mutex);
}
ce face wait-ul?
pthread_cond_wait(&condvar, &mutex);
unlock
permite altor fire sa capete accesul
wait
firul curent asteapta
devine READY
firul nu mai asteapta, dar nu este lansat in executie imediat; se face lock doar dupa
intoarcerea din functie
lock
asigura din nou accesul