• При каждом срабатывании таймера процессу доставляется сигнал, указанный в поле 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] В этой системе сигнал SIGRTMAX имеет номер 64

*sival_ptr = 134524952 sival_ptr указывает на переменную tid

timer_getoverrun() = 0

[15:55:01] Got signal 64

*sival_ptr = 134524952

timer_getoverrun() = 0

Нажимаем Ctrl+Z, чтобы приостановить процесс

[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

Нажимаем Ctrl+C, чтобы завершить программу

В последней строчке программного вывода видно, что таймер имел пять дополнительных срабатываний, то есть с момента доставки предыдущего сигнала он сработал шесть раз.

23.6.6. Дополнительные срабатывания таймера

Допустим, что мы выбрали доставку сигналов в качестве уведомления о срабатывании таймера (то есть аргумент sigev_notify равен SIGEV_SIGNAL). Теперь представьте, что прежде, чем этот сигнал будет перехвачен или принят, таймер успеет сработать еще несколько раз. Это может произойти в результате того, что возобновление работы процесса было запланировано с задержкой. Причиной также может быть блокирование сигнала — либо явное, с помощью вызова sigprocmask(), либо опосредованное, во время выполнения соответствующего обработчика. Как узнать, были ли у таймера дополнительные срабатывания?

Можно предположить, что в решении данной проблемы поможет сигнал реального времени, так как в очередь попало несколько его экземпляров. Однако это предположение неверно, поскольку количество сигналов реального времени, которые могут находиться в очереди, ограничено. Таким образом, комитет, ответственный за стандарт POSIX.1b, решил прибегнуть к другому способу: если выбрать сигнал в качестве средства уведомления о срабатывании таймера, экземпляры этого сигнала никогда не будут складываться в очередь, даже если они работают в режиме реального времени. Вместо этого после получения сигнала (либо через обработчик, либо с помощью вызова sigwaitinfo()) мы можем узнать количество дополнительных срабатываний таймера, которые произошли между моментом создания сигнала и его доставкой. Например, если с момента получения последнего сигнала таймер сработал три раза, счетчик его дополнительных срабатываний будет равен 2.

Приняв сигнал от таймера, мы можем получить количество дополнительных срабатываний. Для этого есть два способа.

• Сделать вызов timer_getoverrun(), который будет описан ниже. Этот вариант определения количества дополнительных срабатываний предусмотрен стандартом SUSv3.

Перейти на страницу:

Похожие книги