Documente Academic
Documente Profesional
Documente Cultură
Curs 10
Timere:
timerele POSIX furnizeaza un mecanism prin care un fir de executie poate fi anuntat ca a expirat un anumit interval de timp (timeout) masurat cu un anumit ceas necesita utilizarea mecanismului de transmitere de semnale al sistemului de operare conform modelului de timere POSIX un timer poate expira:
la o data exprimata in valoare absoluta la o data exprimata in valoare relativa (e.g. n nanosecunde din acest moment) ciclic (i.e. la fiecare n nanosecunde)
Timere:
Apeluri de sistem pentru timere sub QNX Programarea Aplicatiilor in Timp Real. Teorie si Practica", tabelul 6.5, pag. 177
Timere:
timerele sunt considerate a fi o sursa de generare de evenimente in sistem, din care cauza apeleaza la sistemul de livrare a evenimentelor asociat nucleului
o aplicatie poate cere ca orice eveniment suportat de microkernelul Neutrino sa-i fie livrat la expirarea unui timeout din aceasta cauza, expirarea unui timer poate fi semnalizata cu un semnal SIGALRM (asociat functiei alarm()) sau cu orice alt semnal POSIX de timp-real
Timere:
one-shot. Este un timer armat initial cu o valoare de expirare, relativ la momentul curent sau absolut (in functie de o baza de timp). Expira o singura data si apoi este dezarmat; periodic. Este un timer armat initial cu o valoare de expirare, relativ la momentul curent sau absolut, si cu un interval de repetitie. La expirarea intervalului initial, timer-ul este reincarcat cu intervalul de repetitie si continua sa numere
un timer QNX este de fapt o structura de date care trebuie sa fie creata, utilizata o data sau de mai multe ori, si apoi distrusa
Crearea timerelor:
principalele structuri de date pentru manipularea timerelor: Programarea Aplicatiilor in Timp Real. Teorie si Practica", tabelul 6.6, pag. 178
Crearea timerelor:
principalele functii pentru manipularea timerelor: "Programarea Aplicatiilor in Timp Real. Teorie si Practica", tabelul 6.6, pag. 178
Crearea timerelor:
Setarea timerelor:
timer-ul se armeaza prin asocierea unui timp de alarmare si (optional) a unei perioade de repetitie timpul de alarmare poate fi setat relativ (la momentul apelului) sau absolut de exemplu, un timer care va suna prima data dupa o secunda si apoi repetat, la fiecare 50 ms, se instaleaza astfel:
// seteaza parametrul timer-ului la 1 secunda, 0 nanosecunde timer.it_value.tv_sec = 1; timer.it_value.tv_nsec = 0; // seteaza parametrii pentru repetarea automata a timer-ului la 50ms timer.it_interval.tv_sec = 0; timer.it_interval.tv_nsec = 50000000; timer_settime(tid, 0, &timer, NULL);
Setarea timerelor:
= 0:
timer_t tid; ... timer.it_value.tv_sec = 1; timer.it_value.tv_nsec = 0; timer.it_interval.tv_sec = 0; timer.it_interval.tv_nsec = 0; ... timer_settime(tid, 0, &timer, NULL);
Setarea timerelor:
= 0:
timer_t tid; ... timer.it_value.tv_sec = 0; timer.it_value.tv_nsec = 0; timer.it_interval.tv_sec = 0; timer.it_interval.tv_nsec = 50000000; ... timer_settime(tid, 0, &timer, NULL);
posibilitatea de a planifica un timer pentru activare periodica este utila pentru planificarea periodica a firelor de executie un timer este o sursa periodica de evenimente care poate fi utilizata pentru a forta un thread sa se activeze la anumite momente de timp, dupa care sa intre in sleep pana la urmatorul eveniment thread-ul va programa timer-ul o singura data si apoi va raspunde la aparitia periodica a evenimentelor un timer este asemanator unui ceas cu alarma care face o numaratoare inversa pe un anumit interval, semnalizand expirarea acestuia spre deosebire de sleep(), un timer nu suspenda procesul (thread-ul) apelant
un fir de executie isi poate seta ciclic un timer, asteptand un semnal pentru care nu are un handler pentru setarea timer-ului se poate folosi semnalul SIGALRM.
OBSERVATIE:
deoarece semnalele sunt tratate global In cadrul unui proces POSIX, ele nu sunt legate de un anumit thread din cadrul procesului. De aceea, pentru ca acest exemplu sa functioneze, nici un alt thread nu trebuie sa foloseasca semnalul SIGALRM pentru (orice) alt scop sunt necesare doua structuri de lucru, sigevent si itimerspec
Ceasuri si timere:
OBSERVATIE:
kernelul poate replanifica procese si /sau fire de executie in trei situatii: la aparitia unei intreruperi hardware cand se face un apel de sistem (system call) la declararea unei exceptii (fault) exemplu: daca un thread face sleep(), biblioteca C contine cod care in final face apel la o functie (apel) de sistem acest apel scoate thread-ul din coada RUNNING si porneste un timer (countdown) in acelasi timp kernelul primeste intreruperi hardware la intervale egale de la ceasul hardware (de exemplu, la 10 ms) aceste intreruperi sunt tratate de catre rutina de tratare a intreruperilor de ceas a kernelului (ISR)
sursa circuite hardware (capitolul Clocks, Timers, and Getting a Kick Every So Often):
Help QNX Momentics IDE QNX Neutrino Realtime Operating System > Getting Started with QNX Neutrino: A Guide for Realtime Programmers
Timere:
tipuri de timere
relative = perioada de expirare (timeout) este specificata relativ la momentul curent (peste ...) absolute = momentul de expirare (timeout) este specificat exact la momentul dorit (la data de de ...) one-shot = suna o singura data periodic = suna periodic, la intervalul specificat
cum verificam ca a expirat timpul? scheme de notificare OBSERVATIE: daca se face un simplu delay, la expirarea timpului de asteptare procesul sau thread-ul este trecut inapoi in starea READY (gata de executie) in cazul timerelor periodice sau one-shot, se poate: trimite un puls trimite un semnal crea un thread
Pulsuri:
spre deosebire de serviciile sincrone Send/Receive/Reply, nucleul Neutrino suporta si mesaje fara blocare de dimensiune fixa = pulsuri pulsurile sunt mesaje scurte formate din 8 biti de cod si 32 biti de date sunt folosite adesea drept mecanism de notificare n cadrul rutinelor de tratare a ntreruperilor de asemenea, permit serverelor sa notifice clientii, fara a-i bloca se foloseste acelasi mecanism de transmitere de mesaje prin intermediul canalelor de comunicatie sub QNX
Pulsuri:
Interfata C /POSIX pentru mesaje de tip puls "Programarea Aplicatiilor in Timp Real. Teorie si Practica", tabelul 4.3, pag. 144
Scheme de notificare:
in orice schema de notificare se foloseste o structura sigevent detalii ale definitiilor se gasesc in <sys/siginfo.h>
struct sigevent { int sigev_notify; // tipul de notificare union { int sigev_signo; int sigev_coid; int sigev_id; void (*sigev_notify_function) (union sigval); }; union sigval sigev_value; union { struct { short sigev_code; short sigev_priority; }; pthread_attr_t *sigev_notify_attributes; };
};
SIGEV_PULSE se va transmite un puls SIGEV_SIGNAL, SIGEV_SIGNAL_CODE, sau SIGEV_SIGNAL_THREAD se va transmite un semnal SIGEV_UNBLOCK not used in this case; used with kernel timeouts SIGEV_INTR not used in this case; used with interrupts SIGEV_THREAD creaza un thread
deoarece folosim aceasta structura pentru timere, ne intereseaza doar SIGEV_PULSE, SIGEV_SIGNAL si SIGEV_THREAD
se trimite un puls la expirarea timer-ului se seteaza campul sigev_notify la SIGEV_PULSE se transmite informatie suplimentara, astfel:
Utilizarea timerelor:
crearea unui obiect de tip timer se decide schema de notificare (semnal, puls sau creare thread) si se creaza structura de notificare (struct sigevent) se alege tipul de timer (relativ / absolut sau one-shot / periodic) se porneste timerul
Crearea timerelor:
#include <time.h> #include <sys/siginfo.h> int timer_create (clockid_t clock_id, struct sigevent *event, timer_t *timerid);
OBSERVATIE: standardul POSIX spune ca se pot folosi mai multe baze de timp, pe diferite platforme, dar orica platforma trebuie sa suporte cel putin baza de timp data de CLOCK_REALTIME sub Neutrino pot fi alese 3 baze de timp: CLOCK_REALTIME CLOCK_SOFTTIME CLOCK_MONOTONIC
Ce fel de timer:
#include <time.h> int timer_settime (timer_t timerid,int flags, struct itimerspec *value, struct itimerspec *oldvalue);
argumentul timerid este valoarea returnata de functia timer_create() intr-o aplicatie pot fi create mai multe timere si apoi se apeleaza timer_settime() individual pentru fiecare pentru setare si pornire argumentul flags specifica tipul de timer
daca este setat la valoarea constanta TIMER_ABSTIME, timerul va fi de tip absolut daca este setat la zero, timerul va fi considerat relativ la momentul curent
struct timespec { long tv_sec, tv_nsec; }; struct itimerspec { struct timespec it_value, it_interval; };
struct itimerspec are doi membri: it_value the one-shot value it_interval the reload value
Setarea timerelor:
timer-ul se armeaza prin asocierea unui timp de alarmare si (optional) a unei perioade de repetitie timpul de alarmare poate fi setat relativ (la momentul apelului) sau absolut de exemplu, un timer care va suna prima data dupa o secunda si apoi repetat, la fiecare 50 ms, se instaleaza astfel:
timer_t tid; // seteaza parametrul timer-ului la 1 secunda, 0 nanosecunde timer.it_value.tv_sec = 1; timer.it_value.tv_nsec = 0; // seteaza parametrii pentru repetarea automata a timer-ului la 50ms timer.it_interval.tv_sec = 0; timer.it_interval.tv_nsec = 50000000; timer_settime(tid, 0, &timer, NULL);
#define MY_PULSE_CODE
Exemplu - executia periodica prin intermediul timerelor notificare prin pulsuri (cont):
main(){ timer_t tid; struct itimerspec timer; struct sigevent event; int chid, rcvid; tip_mesaj msg; chid = ChannelCreate(0); // pentru notificare se trimite un puls pe un canal de comunicatie event.sigev_notify = SIGEV_PULSE; event.sigev_coid = ConnectAttach(0, 0, chid, _NTO_SIDE_CHANNEL, 0); event.sigev_priority = getprio(0); event.sigev_code = MY_PULSE_CODE; ...
Exemplu - executia ciclica a threadurilor prin intermediul timerelor notificare prin pulsuri (cont):
timer_create(CLOCK_REALTIME, &event, &tid); // timerul este setat la 1.5 secunde timer.it_value.tv_sec = 1; timer.it_value.tv_nsec = 500000000; /* 0.5 secunde */
// intervalul de reprogramare este de 1.5 secunde timer.it_interval.tv_sec = 1; timer.it_interval.tv_nsec = 500000000; timer_settime(tid, 0, &timer, NULL); while(1) { rcvid = MsgReceive(chid, &msg, sizeof(msg), NULL); if (rcvid == 0) /* s-a primit un puls */ if (msg.pulse.code == MY_PULSE_CODE) printf("S-a primit un puls de la timer ... \n"); /* 0.5 secunde */
Exemplu - executia ciclica a threadurilor prin intermediul timerelor notificare prin pulsuri (cont):
rezultatul executiei programului: primit primit primit primit primit un un un un un puls puls puls puls puls de de de de de la la la la la timer timer timer timer timer ... ... ... ... ...
Atentie:
intarzierea unui proces pe un anumit interval de timp: GRESIT: constructie software de tip busy-wait un task asteapta trecerea unui interval de 10 secunde intr-o organizare de tip busy-wait
start := clock; // citeste ceasul loop exit when (clock start) > 10.0; end loop;
corect: se folosesc functiile specificate pentru asteptare, care elibereaza CPU cind taskul se blocheaza asteptand trecerea intervalului de asteptare (sleep, delay, etc)