Documente Academic
Documente Profesional
Documente Cultură
Curs 8
- Semnale-
Cuprins curs 8:
semnale
Semnale:
spre deosebire de mesaje, semnalele sunt indicatoare complet asincrone ale evenimentelor care apar in sistem semnalele mai sunt denumite si intreruperi software, deoarece pot schimba fluxul normal de executie al programului la orice moment de timp si in orice loc al executiei
semnalele pot fi generate intr-un proces ca urmare a unei erori (de exemplu, impartire la zero), a unui eveniment (de exemplu, se tasteaza CTRL-C), sau atunci semnalul este generat de catre un proces (de exemplu, cu functia kill())
Semnale:
semnalele trebuie "tratate" in mod special de procese rutine de tratare a semnalelor (engl. signal handlers) cei trei pasi de procesare asociati semnalelor sunt generarea semnalelor transmiterea semnalelor tratarea semnalelor
Semnale:
Exista trei modalitati in care un proces poate lua in considerare un semnal: procesul poate trata semnalul prin definirea unei functii speciale (engl. signal-handler) care sa fie apelata si sa prinda (catch a signal) semnalul de fiecare data cand acesta este primit; procesul poate ignora in mod explicit semnalul (caz in care semnalul este pierdut), nefiind executata nici o actiune; procesul accepta semnalul in mod implicit, si in acest caz se aplica actiunea default, care in mod normal presupune terminarea procesului
Semnale:
exista un numar predefinit de semnale, fiecaruia fiindu-i alocat un numar intreg exista, de asemenea, un numar de semnale definite de utilizator ce pot fi folosite in aplicatii semnalele sunt identificate prin nume si numar unele semnale sunt asociate evenimentelor care le-au generat (de exemplu, SIGINT, generat de o intrerupere de la tastura) altele nu au asociate evenimente predefinite (de exemplu, SIGUSR1). detalii despre semnale sunt disponibile in biblioteca QNX signal.h exemplu QNX: s-a definit SIGRTMIN pentru primul semnal de timp real si SIGRTMAX pentru ultimul semnal de timp real doar semnalele ale caror numere se afla intre SIGRTMIN si SIGRTMAX sunt considerate semnale POSIX de timp real
Semnale:
un semnal poate
fi livrat (delivery) imediat procesului caruia ii este destinat poate fi blocat (mai tarziu, despre masti de semnal) si livrat mai tarziu
Modalitatile prin care un proces poate genera un semnal care va fi trimis unui alt proces sunt urmatoarele: prin intermediul functiei kill(); cu ajutorul functiei sigqueue(). Aceasta functie poate trimite numai semnale de timp real; cu ajutorul functiei raise().
oricarui proces:
kill(pid_t pid, int signo) sigqueue(pid_t pid, int signo, union sigval value) necesita permisiunea sender-ul trebuie sa fie root sau acelasi user ca si procesul target
actiunea default a celor mai multe semnale este aceea de a termina (engl. kill ) procesul care le primeste, dar este posibil ca aceast comportament implicit sa fie evitat prin folosirea unor handlere se semnal dedicate, definite de programatorul aplicatiei multe semnale sunt generate de erori serioase, cum ar fi cele de memorie sau de caderea tensiunii de alimentare
aceste erori nu pot fi remediate si nu se poate face mare lucru pentru a le evita
pe de alta parte, anumite semnale (de exemplu, SIGCONT) sunt benigne si sunt utilizate doar pentru a atentiona utilizatorul in privinta unui anumit eveniment
o rutina de tratare a semnalului primeste ca parametru doar numarul semnalului receptionat de proces. Orice alta informatie de care este nevoie va fi dedusa din setarile programului (e.g. din variabilele globale: void sig_handler(int sig_no){ if(sig_no == SIGSEGV){ // executa o anumita operatie // } ++sig_count; }
variabila sig_count trebuie sa fie declarata in programul principal, astfel: static volatile sig_atomic_t sig_count = 0;
in general, procesarea semnalelor prin intermediul rutinelor de tratare a semnalelor (handlere de semnal) presupune trei pasi:
definirea semnalului care va fi procesat in rutina; declararea rutinei de tratare a semnalului; instalarea rutinei de tratare a semnalului (cu functia sigaction()).
#define MySig <nr_semnal> // declara handler semnal void handler(int signo, <alti_parametri>){ switch(signo){ case ... : .... case MySig: executa_ceva(); // continua executia taskului din punctul in care a fost intrerupt break; default: break; } } main(){ instaleaza_handler_semnal(handler); ... executa_operatii(); ... }
static volatile sig_atomic_t sig_count = 0; void sig_handler(int sig_no){ if( sig_no == SIGALRM) printf("A expirat alarma! \n"); else if(sig_no == SIGSEGV){ printf("Segment violation! \n"); signal(SIGSEGV, SIG_DFL); } else if(sig_no == SIGCHLD) printf("S-a terminat procesul fiu! \n"); else if(sig_no == SIGINT) printf("Break ! \n"); else if(sig_no == SIGUSR1) printf("Semnal de la user ! \n"); ++sig_count; }
/* ex_schild.c */ #include <stdlib.h> #include <unistd.h> main(void){ printf("Proces fiu ... \n"); sleep(5); exit(123); }
semnalul cu numarul 16, SIGUSR1, poate fi transmis din alt terminal, cu comanda:
OBSERVATIE:
deoarece linia de cod care trateaza semnalul SIGSEGV este comentata, procesul, nu va putea trata acest semnal in rutina si se va termina fortat
Exemplul problema:
Enunt problema: Un cont bancar este utilizat de mai multe persoane (procese). Fiecare persoana poate depozita sau retrage anumite sume de bani din contul comun. Sa se scrie o aplicatie multitasking care va fi formata din urmatoarele tipuri de taskuri:
task depunere: va depune o suma in contul comun (va face o cerere de depunere); task retragere: va incerca sa retraga o suma de bani din contul comun (va face o cerere de retragere); task server: va monitoriza situatia depunerilor / retragerilor in/din contul comun, astfel incat balanta (suma depunerilor minus suma retragerilor, la zi) sa nu fie negativa.
Exemplul:
Cerinte:
sa se analizeze problema si sa se propuna o solutie pentru implementare sa se defineasca taskurile sa se organizeze aplicatia sub forma organigramelor sa se aleaga un mecanism de sinronizare / comunicare (sub QNX) pentru implementare sa se schiteze programul cu functii specifice sub QNX
Exemplul:
presupunem ca un singur task depune, unul singur retrage, si un alt task monitorizeaza balanta cum gandim: dam prioritate taskului(lor) care depune in cont, apoi lasam sa retraga, daca sunt bani suficienti; taskul de monitorizare decide cine depune si cine retrage facem organigramele (toate taskurile se executa in bucla infinita) de exemplu, alegem o solutie cu semafoare
Exemplul:
Task depunere
Task monitorizare
Task retragere
Task initializare
P(SemD)
P(GataD)
depune
V(SemR)
V(GataD)
P(GataR)
V(GataR)
V(SemD)