• При каждом срабатывании таймера процессу доставляется сигнал, указанный в поле sev.sigev_signo. Обработчик сигнала выводит содержимое поля sev.sigev_value.sival_ptr (то есть идентификатор таймера, tidlist[j]) и количество дополнительных срабатываний таймера
• Создав и запустив таймеры, входит в цикл и ждет, когда они сработают, постоянно делая вызов pause()
В листинге 23.6 показана функция, которая конвертирует каждый аргумент командной строки для нашей программы в соответствующую структуру itimerspec. Формат строковых аргументов, интерпретируемых данной функцией, указан в комментарии в верхней части листинга (и продемонстрирован в сессии командной строки чуть ниже).
Листинг 23.6. Преобразование строки с временем и интервалом в значение типа itimerspec
timers/itimerspec_from_str.c
#include
#include
#include "itimerspec_from_str.h" /* Объявляет определяемую здесь функцию */
/* Конвертирует строку следующего формата в структуру itimerspec:
"value.sec[/value.nanosec][: interval.sec[/interval.nanosec]]".
Дополнительные элементы, которые мы опускаем, приводят к обнулению
соответствующих полей структуры. */
void
itimerspecFromStr(char *str, struct itimerspec *tsp)
{
char *dupstr,*cptr, *sptr;
dupstr = strdup(str);
cptr = strchr(dupstr, ':');
if (cptr!= NULL)
*cptr = '\0';
sptr = strchr(dupstr, '/');
if (sptr!= NULL)
*sptr = '\0';
tsp->it_value.tv_sec = atoi(dupstr);
tsp->it_value.tv_nsec = (sptr!= NULL)? atoi(sptr + 1): 0;
if (cptr == NULL) {
tsp->it_interval.tv_sec = 0;
tsp->it_interval.tv_nsec = 0;
} else {
sptr = strchr(cptr + 1, '/');
if (sptr!= NULL)
*sptr = '\0';
tsp->it_interval.tv_sec = atoi(cptr + 1);
tsp->it_interval.tv_nsec = (sptr!= NULL)? atoi(sptr + 1): 0;
}
free(dupstr);
}
timers/itimerspec_from_str.c
В следующей сессии командной строки показан пример использования программы из листинга 23.5. Мы создадим один таймер с начальным временем срабатывания, равным 2 секундам, и интервалом 5 секунд.
$ ./ptmr_sigev_signal 2:5
Timer ID: 134524952 (2:5)
[15:54:56]
*sival_ptr = 134524952 sival_ptr указывает на переменную tid
timer_getoverrun() = 0
[15:55:01] Got signal 64
*sival_ptr = 134524952
timer_getoverrun() = 0
[1]+ Stopped./ptmr_sigev_signal 2:5
Мы приостанавливаем программу на несколько секунд, позволяя таймеру сработать несколько раз:
$ fg
./ptmr_sigev_signal 2:5
[15:55:34] Got signal 64
*sival_ptr = 134524952
timer_getoverrun() = 5
В последней строчке программного вывода видно, что таймер имел пять дополнительных срабатываний, то есть с момента доставки предыдущего сигнала он сработал шесть раз.
23.6.6. Дополнительные срабатывания таймера
Допустим, что мы выбрали доставку сигналов в качестве уведомления о срабатывании таймера (то есть аргумент sigev_notify равен SIGEV_SIGNAL). Теперь представьте, что прежде, чем этот сигнал будет перехвачен или принят, таймер успеет сработать еще несколько раз. Это может произойти в результате того, что возобновление работы процесса было запланировано с задержкой. Причиной также может быть блокирование сигнала — либо явное, с помощью вызова sigprocmask(), либо опосредованное, во время выполнения соответствующего обработчика. Как узнать, были ли у таймера
Можно предположить, что в решении данной проблемы поможет сигнал реального времени, так как в очередь попало несколько его экземпляров. Однако это предположение неверно, поскольку количество сигналов реального времени, которые могут находиться в очереди, ограничено. Таким образом, комитет, ответственный за стандарт POSIX.1b, решил прибегнуть к другому способу: если выбрать сигнал в качестве средства уведомления о срабатывании таймера, экземпляры этого сигнала никогда не будут складываться в очередь, даже если они работают в режиме реального времени. Вместо этого после получения сигнала (либо через обработчик, либо с помощью вызова sigwaitinfo()) мы можем узнать
Приняв сигнал от таймера, мы можем получить количество дополнительных срабатываний. Для этого есть два способа.
• Сделать вызов timer_getoverrun(), который будет описан ниже. Этот вариант определения количества дополнительных срабатываний предусмотрен стандартом SUSv3.