Механизмите на таймера ви позволяват да планирате ядрото на ОС да уведомява приложение, когато е изтекло предварително определено време. Обикновено ще ги използвате, като предоставите две части информация. Първо, ще трябва да посочите колко време трябва да отнеме таймерът, преди да уведомите. Второ, ще трябва да подготвите функция за обратно извикване, която да действа, когато се появи това известие.
Традиционен подход към таймерите
Механизмите на таймера в базираните на Linux и Unix системи са се развили, за да обслужват различни нужди. Различните подходи могат да ви помогнат да решите различни видове проблеми. Въпреки това, често ще виждате първата версия на аларма() механизъм все още се използва.
Функцията за аларма е най-простият начин за използване на таймер; ето неговия прототип:
неподписанмеждународеналарма(неподписанмеждународен секунди);
Използвайки този метод, можете да посочите времето само в цели секунди. Когато времето изтече, операционната система изпраща SIGALRM сигнал към вашето приложение. За да обработите изтичането на таймера във вашето приложение, трябва също да дефинирате функция за обратно извикване.
Ето пример за функция за обработка на сигнали:
#включват
#включват
#включват
#включватнищоженtimer_callback(международен signum)
{
time_t сега = време(НУЛА);
printf(„Сигнал %d е хванат на %li“, signum, сега);
}
международенглавен()
{
сигнал (SIGALRM, timer_callback);
аларма(1);
сън (3);
връщане0;
}
Този код повдига a SIGALRM сигнал след 1 второ. Ако искате да увеличите закъснението на таймера до пет секунди, просто се обадете аларма (5) вместо. За да спрете таймера, предайте стойност 0: аларма (0).
Когато времето изтече, таймерът, който използвате, няма да се рестартира периодично. Например, ако искате да забавите още секунда, трябва да рестартирате механизма с друго извикване към аларма().
Въпреки лекотата на използване, този метод има някои недостатъци:
- Само един таймер в даден момент.
- Няма поддръжка на периодичен таймер.
- Можете да дадете период от време само в кратни на цели секунди.
- Няма начин да разберете колко време остава на таймер.
Запазете примерния код, даден по-горе, като аларма.c. Кога компилирате и стартирате го, програмата ще извика timer_callback функция след една секунда. След това ще изчака оставащите две секунди поради сън (3) линия, след което прекратете.
$ gcc -o аларма аларма.c
$ време ./аларма
Сигнал 14 е хванат на 1653490465
реални 0m1.004s
потребител 0m0.000s
sys 0m0.003s
Причината за използване на командата time е да можете да виждате времената. Но ако погледнете резултата, общото време на работа не е три секунди. Това се дължи на SIGALRM сигнал от аларма (1) когато изтече първата секунда, докато системно извикване причинено от работата на функцията за сън (3). Когато този сигнал пристигне, той прекъсва системното повикване, инициирано за сън (3).
Използване на интервален таймер
Механизмът на интервалния таймер беше наличен за първи път във версия 4.2 BSD. Беше по-късно стандартизиран от POSIX. Основните му предимства пред традиционните аларма() базиран метод на таймер са:
- Осигурява микросекундна разделителна способност.
- Позволява по-подробно контролиране на измерването на времето в три различни режима.
- Възможно е да го настроите веднъж и да го накарате да работи периодично.
- Възможно е да разберете колко дълго е налице във всеки един момент.
Прототипите на функциите, използвани за операции на интервалния таймер, са както следва:
#включват
международенsetitimer(международен който, const struct itimerval *newValue, struct itimerval *oldValue);
международенgetitimer(международен което, struct itimerval *стойност);структураitimerval
{
структуравремеви периодitInterval;// следващата стойност
структуравремеви периодitValue;// текуща стойност
};
структуравремеви период
{
дълго tv_sec;
дълго tv_usec;
};
Ако искате да настроите интервален таймер, ще трябва да използвате itimerval структура. Ще трябва да предадете стойност, използвайки тази структура като втори аргумент на таймер за настройка функция.
Например, интервален таймер, който ще уведомява приложението ви за 1 секунда и след това на всеки 300 милисекунди, може да бъде настроен, както следва:
структураitimervalнов таймер;
структураitimervalолдтаймер;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);
Ако има активен интервален таймер преди да бъдат зададени новите стойности, неговите стойности се прехвърлят към адреса на променливата на itimerval тип, даден на третия параметър на функцията.
Можете да настроите три различни типа таймери с механизма на интервалния таймер. Посочете типа таймер в първия параметър на setitimer():
Тип таймер | Сигнал | Обяснение |
---|---|---|
ITIMER_REAL | SIGALRM | Независимо от времето, прекарано от приложението, изчислено за общото изминало време. |
ITIMER_VIRTUAL | SIGVTALRM | Изчислено за времето, когато приложението работи само в потребителски режим. |
ITIMER_PROF | SIGPROF | Изчислява се върху сумата от времето, прекарано от приложението както в потребителския, така и в системния режим. |
От тази таблица можете да видите, че ITIMER_REAL тип изпраща a SIGALRM сигнал, точно като аларма() функция.
Използване на интервален таймер и аларма() в същото приложение ще бъде объркващо. Въпреки че можете да направите втора проверка на оставащото време с gettimer(), няма смисъл да ги използвате едновременно.
Ето пример за дефиниране на функцията за обработка на сигнали с заглавка за отстраняване на грешки:
#включват
#включват
#включват
#включват
#включват
#включват
#включват
#включват "./debug.h"нищоженtimer_callback(международен signum)
{
структуравремеви периодсега;
gettimeofday(&сега, НУЛА);
printf(„Сигнал %d е уловен на %li.%03лi ", signum, now.tv_sec, now.tv_usec / 1000);
}международенглавен()
{
неподписанмеждународен остава = 3;структураitimervalнов_таймер;
структураitimervalold_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);
сигнал (SIGALRM, timer_callback);докато (сън (оставащ) != 0)
{
ако (грешно == EINTR)
debugf("спянето е прекъснато от сигнал");
друго
errorf("грешка при заспиване %s", strerror (errno));
}
връщане0;
}
Горният код използва спя () функция да изчака три секунди. През това време таймерът за интервал работи първо за една секунда, след това на интервал от 300 милисекунди.
За по-добро разбиране запазете и компилирайте примерния код с името интервал.в:
$ gcc -o интервал интервал.c
$ време ./интервал
Сигнал 14 е уловен на 1653493614.325
отстраняване на грешки: сънят е прекъснат от сигнал (главен интервал.c: 36)
Сигнал 14 е уловен на 1653493614.625
отстраняване на грешки: сънят е прекъснат от сигнал (главен интервал.c: 36)
Сигнал 14 е хванат на 1653493614.925
отстраняване на грешки: сънят е прекъснат от сигнал (главен интервал.c: 36)
Сигнал 14 хванат на 1653493615.225
отстраняване на грешки: сънят е прекъснат от сигнал (главен интервал.c: 36)
Сигнал 14 е хванат на 1653493615.525
...
Както можете да видите от изхода след стартиране на таймера, той извиква функцията за обратно извикване на всеки 300 милисекунди.
Въпреки това, след като изчакате още малко, ще забележите, че приложението не се прекратява. Той продължава да изпълнява функцията за обратно извикване на всеки 300 милисекунди. Ако увеличите стойността на интервала в милисекунди, ще видите, че приложението приключва. Това се дължи на зоната на използване на спя () функция.
Значението на използването на таймери в Linux
Особено за приложения в реално време механизмът на таймера е от голямо значение. Това също е решение, използвано за оптимизиране на производителността. Можете дори да го използвате за измерване на времето за работа или латентността във вашето приложение. Важно е да използвате механизми на таймера, за да следите изминалото време и събитията за преход на време.
Как да компилирате и инсталирате софтуер от източник в Linux
Прочетете Следващото
Свързани теми
- Програмиране
- Програмиране
- Съвети за Linux
За автора
Инженер и разработчик на софтуер, който е фен на математиката и технологиите. Винаги е харесвал компютрите, математиката и физиката. Той е разработил проекти на двигатели за игри, както и машинно обучение, изкуствени невронни мрежи и библиотеки с линейна алгебра. Освен това продължава да работи върху машинно обучение и линейни матрици.
Абонирайте се за нашия бюлетин
Присъединете се към нашия бюлетин за технически съвети, ревюта, безплатни електронни книги и ексклузивни оферти!
Щракнете тук, за да се абонирате