Download as pdf or txt
Download as pdf or txt
You are on page 1of 39

PROGRAMAREA APLICAŢIILOR

ÎN
TIMP-REAL

Curs 4

18-Mar-16 Programarea Aplicatiilor in Timp-Real 1


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, ...

18-Mar-16 Programarea Aplicatiilor in Timp-Real 2


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

18-Mar-16 Programarea Aplicatiilor in Timp-Real 3


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

18-Mar-16 Programarea Aplicatiilor in Timp-Real 4


Fire de executie – parametrii de planificare:

 setarea prioritatii si algoritmului de planificare

 amandoua:
struct sched_param param;
pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
param.sched_priority = 15;
pthread_attr_setschedparam (&attr, &param);
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, &param);
pthread_attr_setschedpolicy (&attr, SCHED_NOCHANGE);
pthread_create (NULL, &attr, func, arg);

18-Mar-16 Programarea Aplicatiilor in Timp-Real 5


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 se termine (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 hasn’t already
pthread_join (tid, &return_status);
 daca se termina 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

18-Mar-16 Programarea Aplicatiilor in Timp-Real 6


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 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);

18-Mar-16 Programarea Aplicatiilor in Timp-Real 7


Fire de executie – operatii asupra firelor de executie:

 cateva operatii asupra firelor de executie:

pthread_exit(retval) terminate the calling thread


pthread_kill(tid, signo) set signal signo on thread tid
pthread_detach(tid) make the thread detached (i.e. unjoinable)
tid = pthread_self() find out your thread id
pthread_equal (tid1, tid2) compare two thread ids

18-Mar-16 Programarea Aplicatiilor in Timp-Real 8


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

18-Mar-16 Programarea Aplicatiilor in Timp-Real 9


Fire de executie - exemplu:

 program pentru calculul valorii unui polinom


 exemplul anterior

18-Mar-16 Programarea Aplicatiilor in Timp-Real 10


Probleme caracteristice ale proiectarii aplicatiilor software in timp-
real:

 sincronizarea taskurilor

 excluderea mutuala (pentru acces la resurse partajate)


 comunicarea intre taskuri

 aspecte colaterale:

– deadlock
– starvation

18-Mar-16 Programarea Aplicatiilor in Timp-Real 11


In continuare:

 excludere mutuala – definitie

 excludere mutuala – modalitati de implementare


 mecanisme de implementare a operatiilor de excludere mutuala
 semafoare binare
 mutex-uri

 exemple: problema producator - consumator

18-Mar-16 Programarea Aplicatiilor in Timp-Real 12


Excluderea mutuala - definitie:

 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

 fiecare din taskurile care acceseaza


resursa partajata executa o
sectiune (zona) critica
(adica o secventa de instructiuni cu care se
acceseaza resursele partajate – imprimanta,
zone de date comune, etc)

 un singur task poate executa sectiunea critica la un moment dat, restul fiind blocate

 mecanisme pentru implementarea excluderii mutuale


 semafoare binare, mutex-uri (caz particular de semafor binar)
 monitoare
 transmitere de mesaje

18-Mar-16 Programarea Aplicatiilor in Timp-Real 13


Excluderea mutuala:

 se realizeaza cu semafoare binare

 este initializat cu valoarea 1

 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);

18-Mar-16 Programarea Aplicatiilor in Timp-Real 14


Excluderea mutuala - conditii:

 solutiile de implementare trebuie sa asigure urmatoarele conditii:

 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

18-Mar-16 Programarea Aplicatiilor in Timp-Real 15


Excluderea mutuala:
 la executie, regiunile critice sunt serializate, restul de activitati se executa in paralel

 3 procese care acceseaza o zona comuna de date

18-Mar-16 Programarea Aplicatiilor in Timp-Real 16


Excluderea mutuala – exemplu important:
 comunicarea prin zona comuna de memorie / date

 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

 exemplu: fisierele mapate in QNX


(la laborator)

18-Mar-16 Programarea Aplicatiilor in Timp-Real 17


Excluderea mutuala – exemplu: problema producator -
consumator:

 o aplicatie formata din doua (tipuri de) taskuri

 task producator: “genereaza” date (periodic) - “produce date”


 task consumator: utilizeaza datele produse de taskul producator - “consuma date”

 conditii pentru functionare corecta:

 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)

 presupunem, pentru simplitate, comunicarea prin zona comuna de date, careia i se


ataseaza un semafor binar S pentru excludere mutuala, cu valoare initiala 1

18-Mar-16 Programarea Aplicatiilor in Timp-Real 18


Excluderea mutuala – exemplu: problema producator –
consumator - solutie:

 solutie de implementare cu doua semafoare binare, cu urmatoarea semnificatie:

 S1 = "1" : producatorul are un set de date noi


 S2 = "1" : consumatorul a preluat un set de date si poate primi un set nou

 valorile initiale ale semafoarelor sunt S = 1, S1 = 0, S2 = 1

18-Mar-16 Programarea Aplicatiilor in Timp-Real 19


Excluderea mutuala – exemplu: problema producator –
consumator - solutie:
 solutie de implementare cu buffer asociat, de dimensiune finita

 poate memora N date si poate fi considerat ca o coada circulara


 asupra lui se executa operatii de citire / scriere de tip mod(N)

Blocat Deblocat
Task inserare în buffer plin inserare item
producator
Task scoate din buffer gol scoate item
consumator

18-Mar-16 Programarea Aplicatiilor in Timp-Real 20


Excluderea mutuala – exemplu: problema producator
– consumator - solutie:
 solutia se implementeaza cu semafoare generalizate:

Initializari (global):

const int N; // dimensiune buffer


SB = 1; //semaforul binar pentru sectiunea critica
GOL = 0; //semafor general pentru buffer gol
PLIN = N; // semafor general pentru buffer plin
in = out = 0; // indicii de scriere / citire in / din buffer

18-Mar-16 Programarea Aplicatiilor in Timp-Real 21


Excluderea mutuala – exemplu: problema producator –
consumator - solutie:

 in taskul producator se produc date


 in taskul consumator se consuma date
task_producator()
{
produce_date(); //produce item v si il scrie in
//buffer in urmatoarea pozitie libera
b[in] = v;
in = (in + 1)%n;
}

task_consumator()
{
// citeste item-ul w din buffer si actualizeaza
// pozitia de citire
w = b[out];
out = (out + 1)%n;
consuma_date();
}

18-Mar-16 Programarea Aplicatiilor in Timp-Real 22


Excludere mutuala - mutex-uri:

 in anumite sisteme, semafoarele binare se folosesc numai pentru excludere mutuala si se


numesc "lock". In acest caz primitivele sunt urmatoarele:

lock()
... sectiune critica
unlock()

 exemplu: QNX

 exista mutex-uri (mutual exclusion locks) pentru realizarea sincronizarii in cazul


firelor de executie create in cadrul unui proces
 semafoarele de folosesc in special pentru procese

18-Mar-16 Programarea Aplicatiilor in Timp-Real 23


18-Mar-16 Programarea Aplicatiilor in Timp-Real 24
Excludere mutuala - mutex-uri:

• 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).

 Un singur fir de executie poate incuia un mutex la un moment dat.

 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

18-Mar-16 Programarea Aplicatiilor in Timp-Real 25


18-Mar-16 Programarea Aplicatiilor in Timp-Real 26
18-Mar-16 Programarea Aplicatiilor in Timp-Real 27
Mutex-uri (exemplu):

 o aplicatie formata din doua fire de executie care incrementeaza un contor (resursa partajata)

 crearea firelor de executie:

void* (*functie[])(int*) = {functie1, functie2};

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;
}

for(i=0; i<2; i++)


if(pthread_join(*(FIR+i), NULL) != 0){
perror("pthread_join");
return EXIT_FAILURE;
}

printf("Main: firele s-au terminat. Contor final = %d \n", contor);


pthread_exit(NULL);
}

18-Mar-16 Programarea Aplicatiilor in Timp-Real 28


Mutex-uri (exemplu, cont.):

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;


int contor = 0;
int r[] = {2, 3};

void* functie1(int *iteratii){


int i, it;

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);
}
}

void* functie2(int *iteratii){


int i, it;

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

 alte mecanisme de sincronizare si comunicatie intre procese


– variabile conditionale
– bariere
– sleepon locks
– reader / writer locks

– transmitere de mesaje

18-Mar-16 Programarea Aplicatiilor in Timp-Real 30


Variabile conditionale (engl. condvars):

 situatie: un fir de executie trebuie sa se blocheze, asteptand ca un alt fir sa


modifice o variabila:

int state;
thread_1()
{
while(1){
// wait pana cand "state" se modifica
// apoi executa ceva
}
}

 se rezolva cu condvars

18-Mar-16 Programarea Aplicatiilor in Timp-Real 31


Variabile conditionale (engl. condvars):

 exemplu: o aplicatie software citeste date si le transmite catre un dispozitiv extern (hardware)

 definim 2 fire de executie:


 un fir citeste date de la o anumita sursa
 un alt fir asteapta datele si apoi le transmite catre un dispozitiv

(1) primul fir primeste datele (e.g. de la un proces client), si le pune intr-un buffer si

(2) anunta firul 2 ca datele sunt gata


(3) firul 2 se "trezeste", preia datele din buffer si le transmite catre dispozitiv (extern)
 avem nevoie de :

 un mutex pentru ca cele doua fire sa nu acceseze bufferul in acelasi timp


 un mecanism de notificare a firului 2 ("datele sunt disponibile")
18-Mar-16 Programarea Aplicatiilor in Timp-Real 32
Variabile conditionale (engl. condvars):

 o variabila conditionala este folosita pentru a bloca un fir de executie in interiorul sectiunii critice,
pana cand este indeplinita o anumita conditie

 conditia poate fi de orice natura si complexitate, fiind independenta de variabila conditionala

 operatii pe o variabila conditionala:

 wait (prin apelul functiei pthread_cond_wait()


 signal (prin apelul functiei pthread_cond_signal()
 broadcast (prin apelul functiei pthread_cond_broadcast()

 o variabila conditionala poate fi utilizata impreuna cu un mutex pentru a implementa un monitor

18-Mar-16 Programarea Aplicatiilor in Timp-Real 33


18-Mar-16 Programarea Aplicatiilor in Timp-Real 34
Variabile conditionale (engl. condvars):

 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()

18-Mar-16 Programarea Aplicatiilor in Timp-Real 35


Variabile conditionale (engl. condvars):

 cod pentru firul de executie care pune datele in buffer:

pthread_mutex_lock(&mutex); // acces exclusiv

scrie_in_buffer();

data_ready = 1; // seteaza flag

pthread_cond_signal(&cond); // notifica

pthread_mutex_unlock(&mutex);// eliberare acces exclusiv

18-Mar-16 Programarea Aplicatiilor in Timp-Real 36


Variabile conditionale (engl. condvars):

 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);

// citeste datele din buffer si le trimite la disp

while((data = get_data_and_remove_from_queue()) != NULL){


pthread_mutex_unlock(&mutex);
write_to_hardware(data);
free(data);
pthread_mutex_lock(&mutex);
}

data_ready = 0;
pthread_mutex_unlock(&mutex);
}

18-Mar-16 Programarea Aplicatiilor in Timp-Real 37


Variabile conditionale (engl. condvars):

 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

18-Mar-16 Programarea Aplicatiilor in Timp-Real 38


Bibliografie

 Variabile conditionale - “Programarea aplicatiilor in timp real”, sectiunea 3.4,


pag. 112
 Help IDE Momentics

18-Mar-16 Programarea Aplicatiilor in Timp-Real 39

You might also like