Листинг 23.1. Использование таймера реального времени
timers/real_timer.c
#include
#include
#include
#include "tlpi_hdr.h"
static volatile sig_atomic_t gotAlarm = 0;
/* Устанавливаем ненулевое значение при получении SIGALRM */
/* Получаем и выводим реальное время, а также (если 'includeTimer'
равно true) текущее значение и интервал таймера ITIMER_REAL */
static void
{
struct itimerval itv;
static struct timeval start;
struct timeval curr;
static int callNum = 0; /* Количество вызовов данной функции */
if (callNum == 0) /* Инициализируем счетчик прошедшего времени */
if (gettimeofday(&start, NULL) == –1)
errExit("gettimeofday");
if (callNum % 20 == 0) /* Выводим заголовок через каждые 20 строк */
printf(" Elapsed Value Interval\n");
if (gettimeofday(&curr, NULL) == –1)
errExit("gettimeofday");
printf("%-7s %6.2f", msg, curr.tv_sec — start.tv_sec +
(curr.tv_usec — start.tv_usec) / 1000000.0);
if (includeTimer) {
if (getitimer(ITIMER_REAL, &itv) == –1)
errExit("getitimer");
printf(" %6.2f %6.2f",
itv.it_value.tv_sec + itv.it_value.tv_usec / 1000000.0,
itv.it_interval.tv_sec + itv.it_interval.tv_usec / 1000000.0);
}
printf("\n");
callNum++;
}
static void
sigalrmHandler(int sig)
{
}
int
main(int argc, char *argv[])
{
struct itimerval itv;
clock_t prevClock;
int maxSigs; /* Количество сигналов, которые нужно перехватить до выхода */
int sigCnt; /* Количество уже перехваченных сигналов */
struct sigaction sa;
if (argc > 1 && strcmp(argv[1], "-help") == 0)
usageErr("%s [secs [usecs [int-secs [int-usecs]]]]\n", argv[0]);
sigCnt = 0;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = sigalrmHandler;
errExit("sigaction");
/* Выходим после трех сигналов или при первом срабатывании, если интервал равен 0 */
maxSigs = (itv.it_interval.tv_sec == 0 &&
itv.it_interval.tv_usec == 0)? 1: 3;
displayTimes("START: ", FALSE);
/* Устанавливаем таймер с помощью аргументов командной строки */
itv.it_value.tv_sec = (argc > 1)? getLong(argv[1], 0, "secs"): 2;
itv.it_value.tv_usec = (argc > 2)? getLong(argv[2], 0, "usecs"): 0;
itv.it_interval.tv_sec = (argc > 3)? getLong(argv[3], 0, "int-secs"): 0;
itv.it_interval.tv_usec = (argc > 4)? getLong(argv[4], 0, "int-usecs"): 0;
errExit("setitimer");
prevClock = clock();
sigCnt = 0;
/* Внутренний цикл потребляет как минимум 0,5 секунды процессорного времени */
while (((clock() — prevClock) * 10 / CLOCKS_PER_SEC) < 5) {
gotAlarm = 0;
displayTimes("ALARM: ", TRUE);
sigCnt++;
printf("That's all folks\n");
exit(EXIT_SUCCESS);
}
}
}
prevClock = clock();
displayTimes("Main: ", TRUE);
}
}
timers/real_timer.c
Системный вызов alarm() предоставляет более простой интерфейс для установки таймеров реального времени, которые срабатывают только один раз, без повторения с регулярным интервалом (на самом деле это первый программный интерфейс UNIX для установки таймера).
#include
unsigned int alarm(unsigned int
Всегда завершается успешно, возвращая количество секунд, оставшихся до срабатывания предыдущего таймера, или 0, если таймер ранее не устанавливался
Аргумент seconds обозначает количество секунд, по истечении которых произойдет срабатывание таймера. В этот момент вызывающему процессу будет доставлен сигнал SIGALRM.
Вызов alarm() переопределяет любой ранее установленный таймер. Чтобы выключить имеющийся таймер, можно сделать вызов alarm(0).
В качестве итогового значения alarm() возвращает количество секунд, оставшихся до срабатывания предыдущего таймера, или 0, если такового не обнаружено.
Пример использования вызова alarm() показан в разделе 23.3.
В некоторых примерах, которые будут представлены в этой книге, вызов alarm() применяется для запуска таймера без предварительной установки соответствующего обработчика SIGALRM. Это позволяет гарантировать, что, если процесс не завершится самостоятельно, его работа будет остановлена по истечении определенного времени.