Mecanismele de cronometru vă permit să programați nucleul sistemului de operare pentru a notifica o aplicație când a trecut un timp prestabilit. De obicei, le veți folosi furnizând două informații. În primul rând, va trebui să specificați cât timp ar trebui să dureze cronometrul înainte de a notifica. În al doilea rând, va trebui să pregătiți o funcție de apel invers pentru a acționa atunci când apare notificarea.

Abordarea tradițională a cronometrelor

Mecanismele de cronometru în sistemele bazate pe Linux și Unix au evoluat pentru a satisface diferite nevoi. Abordări diferite vă pot ajuta să rezolvați diferite tipuri de probleme. Cu toate acestea, veți vedea adesea prima versiune a alarma() mecanism încă în uz.

Funcția de alarmă este cea mai simplă modalitate de a folosi un cronometru; iată prototipul său:

nesemnatintalarma(nesemnatint secunde);

Folosind această metodă, puteți specifica timpul doar în secunde întregi. Când timpul expiră, sistemul de operare trimite SIGALRM semnal pentru aplicația dvs. Pentru a procesa expirarea temporizatorului în aplicația dvs., ar trebui să definiți și o funcție de apel invers.

instagram viewer

Iată un exemplu de funcție de gestionare a semnalului:

#include
#include
#include
#include

goltimer_callback(int semnum)
{
time_t acum = timp(NUL);
printf(„Semnal %d prins pe %li”, signum, acum);
}

intprincipal()
{
semnal (SIGALRM, timer_callback);
alarma(1);
dormi(3);
întoarcere0;
}

Acest cod ridică a SIGALRM semnal după 1 al doilea. Dacă doriți să măriți întârzierea temporizatorului la cinci secunde, sunați alarma (5) in schimb. Pentru a opri temporizatorul, treceți o valoare de 0: alarma (0).

Când timpul expiră, cronometrul pe care îl utilizați nu va reporni periodic. De exemplu, dacă doriți să amânați încă o secundă, ar trebui să reporniți mecanismul cu un alt apel către alarma().

În ciuda ușurinței sale de utilizare, această metodă are câteva dezavantaje:

  • Doar un temporizator la un moment dat.
  • Fără suport periodic pentru cronometru.
  • Puteți da perioada de timp doar în multipli de secunde întregi.
  • Nu există nicio modalitate de a ști cât timp rămâne pe un cronometru.

Salvați exemplul de cod dat mai sus ca alarma.c. Când compilați și rulați acesta, programul va apela timer_callback funcţionează după o secundă. Apoi va aștepta cele două secunde rămase din cauza somn (3) linie, apoi terminați.

$ gcc -o alarmă alarmă.c
$ timp ./alarma
Semnalul 14 prins la 1653490465
0m1.004s reale
utilizator 0m0.000s
sys 0m0.003s

Motivul utilizării comenzii time este acela de a putea vedea orele. Dar dacă te uiți la rezultat, timpul total de rulare nu este de trei secunde. Acest lucru se datorează SIGALRM semnal de la alarma (1) când prima secundă este în sus, în timp ce syscall cauzată de funcționarea funcției de somn (3). Când sosește acest semnal, întrerupe apelul sistem inițiat pentru somn (3).

Utilizarea unui temporizator cu intervale

Mecanismul cronometrului de interval a fost disponibil pentru prima dată în versiunea 4.2 BSD. A fost mai târziu standardizat de POSIX. Principalele sale avantaje față de tradițional alarma() metoda timer-ului bazată este:

  • Oferă rezoluție în microsecunde.
  • Permite controlul măsurării timpului mai detaliat în trei moduri diferite.
  • Este posibil să îl setați o dată și să îl faceți să funcționeze periodic.
  • Este posibil să aflați cât timp este prezent în orice moment.

Prototipurile de funcții utilizate pentru operațiunile cu temporizator de intervale sunt după cum urmează:

#include

intsetitimer(int care, const struct itimerval *newValue, struct itimerval *oldValue);
intgettimer(int care, struct itimerval *valoare);

structitimerval
{
structtimevalitInterval;// următoarea valoare
structtimevalitValue;// Valoarea curentă
};

structtimeval
{
lung tv_sec;
lung tv_usec;
};

Dacă doriți să configurați un temporizator de interval, va trebui să utilizați itimerval struct. Va trebui să transmiteți o valoare folosind această structură ca al doilea argument la setari funcţie.

De exemplu, un temporizator de intervale care va notifica aplicația dumneavoastră timp de 1 secundă și apoi la fiecare 300 de milisecunde poate fi configurat după cum urmează:

structitimervalNewTimer;
structitimervalOldTimer;

newTimer.itValue.tv_sec = 1;
newTimer.itValue.tv_usec = 0;

newTimer.itInterval.tv_sec = 0;
newTimer.itInterval.tv_usec = 300 * 1000;

setitimer (ITIMER_REAL, &newTimer, &oldTimer);

Dacă există un temporizator de interval activ înainte ca noile valori să fie setate, valorile acestuia sunt transferate la adresa variabilă a itimerval tip dat celui de-al treilea parametru al funcției.

Puteți configura trei tipuri diferite de cronometre cu mecanismul de cronometru cu intervale. Specificați tipul de cronometru în primul parametru al setitimer():

Tip cronometru Semnal Explicaţie
ITIMER_REAL SIGALRM Independent de timpul petrecut de aplicație, calculat pe timpul total scurs.
ITIMER_VIRTUAL SIGVTALRM Calculat de-a lungul timpului în care aplicația rulează numai în modul utilizator.
ITIMER_PROF SIGPROF Calculat pe suma timpului petrecut de aplicație atât în ​​modul utilizator, cât și în modul sistem.

Puteți vedea din acest tabel că ITIMER_REAL tip trimite a SIGALRM semnal, la fel ca alarma() funcţie.

Folosind un cronometru de interval și alarma() în aceeași aplicație va fi confuz. Deși puteți face o a doua verificare a timpului rămas cu gettimer(), nu are sens să le folosești simultan.

Iată un exemplu de definire a funcției de gestionare a semnalului cu antet de depanare:

#include
#include
#include
#include
#include
#include
#include
#include „./debug.h”

goltimer_callback(int semnum)
{
structtimevalacum;
gettimeofday(&acum, NUL);
printf(„Semnal %d prins pe %li.%03li ", signum, now.tv_sec, now.tv_usec / 1000);
}

intprincipal()
{
nesemnatint rămas = 3;

structitimervalnew_timer;
structitimervalold_timer;

new_timer.it_value.tv_sec = 1;
new_timer.it_value.tv_usec = 0;
new_timer.it_interval.tv_sec = 0;
new_timer.it_interval.tv_usec = 300 * 1000;

setitimer (ITIMER_REAL, &new_timer, &old_timer);
semnal (SIGALRM, timer_callback);

in timp ce (somn (rămâne) != 0)
{
dacă (errno == EINTR)
debugf("somn întrerupt de semnal");
altfel
errorf("eroare de somn %s", strerror (errno));
}

întoarcere0;
}

Codul de mai sus folosește dormi() funcția să aștepte trei secunde. În acest timp, rulează un cronometru de interval, mai întâi pentru o secundă, apoi pe un interval de 300 de milisecunde.

Pentru o mai bună înțelegere, salvați și compilați exemplul de cod cu numele interval.c:

$ gcc -o interval interval.c
$ timp ./interval
Semnalul 14 prins pe 1653493614.325
depanare: somn întrerupt de semnal (interval principal.c: 36)
Semnalul 14 prins pe 1653493614.625
depanare: somn întrerupt de semnal (interval principal.c: 36)
Semnalul 14 prins pe 1653493614.925
depanare: somn întrerupt de semnal (interval principal.c: 36)
Semnalul 14 prins pe 1653493615.225
depanare: somn întrerupt de semnal (interval principal.c: 36)
Semnalul 14 prins pe 1653493615.525
...

După cum puteți vedea din ieșire, după ce cronometrul rulează, apelează funcția de apel invers la fiecare 300 de milisecunde.

Cu toate acestea, după ce mai așteptați puțin, veți observa că aplicația nu se încheie. Continuă să ruleze funcția de apel invers la fiecare 300 de milisecunde. Dacă creșteți valoarea intervalului în milisecunde, veți vedea că aplicația se încheie. Acest lucru se datorează zonei de utilizare a dormi() funcţie.

Importanța utilizării cronometrelor în Linux

În special pentru aplicațiile în timp real, mecanismul cronometrului este de mare importanță. Aceasta este, de asemenea, o soluție folosită pentru optimizarea performanței. Îl puteți folosi chiar și pentru a măsura timpul de funcționare sau latența în aplicația dvs. Este important să folosiți mecanisme de cronometru pentru a urmări timpul scurs și evenimentele de tranziție a timpului.

Cum să compilați și să instalați software din sursă în Linux

Citiți în continuare

AcțiuneTweetAcțiuneE-mail

Subiecte asemănătoare

  • Programare
  • Programare
  • Sfaturi pentru Linux

Despre autor

Fatih Küçükkarakurt (10 articole publicate)

Un inginer și dezvoltator de software care este un fan al matematicii și al tehnologiei. Întotdeauna i-au plăcut computerele, matematica și fizica. El a dezvoltat proiecte de motoare de jocuri, precum și învățare automată, rețele neuronale artificiale și biblioteci de algebră liniară. În plus, continuă să lucreze la învățarea automată și la matrice liniare.

Mai multe de la Fatih Küçükkarakurt

Aboneaza-te la newsletter-ul nostru

Alăturați-vă buletinului nostru informativ pentru sfaturi tehnice, recenzii, cărți electronice gratuite și oferte exclusive!

Click aici pentru a te abona