Возникает вопрос о правильной установке таймаутов таймера.
С настройками
timerValue.it_value.tv_sec = 1;
timerValue.it_value.tv_nsec = 0;
timerValue.it_interval.tv_sec = 1;
timerValue.it_interval.tv_nsec = 0;
Вы правильно выставляете начальный тайм-аут на 1с (поле timerValue.it_value
). Но вы также устанавливаете период c интервал из единиц, и вы не упомянули о желании сделать это.
О тайм-аутах
Это поведение описано в следующем отрывке из руководства:
int timerfd_create(int clockid, int flags);
new_value.it_value
указывает начальное время истечения таймера в секундах и наносекундах. Установка любого поля new_value.it_value
на ненулевое значение включает таймер.
Установка обоих полей new_value.it_value
на ноль снимает с охраны таймер.
Установка одного или обоих полей new_value.it_interval
на ненулевые значения указывает период в секундах и наносекундах для повторного истечения таймера после начального истечения. Если оба поля new_value.it_interval
равны нулю, таймер истекает только один раз, во время, указанное в new_value.it_value
.
Последний абзац сделан мной, так как он показывает, что нужно сделать, чтобы иметь таймер однократного действия.
Преимущества timerrfd
. Как определить истечение времени таймера?
Основное преимущество, предоставляемое timerfd
, заключается в том, что таймер связан с файловым дескриптором, а это означает, что
может контролироваться select
(2) , poll
(2) и epoll
(7) .
Информация Содержащийся в другом ответе о read()
также действителен: давайте просто скажем, что даже при использовании таких функций, как select()
, функция read()
потребуется для использования данных в файловом дескрипторе.
Полный пример
В следующей демонстрационной программе установлен тайм-аут 4 секунды; после этого устанавливается интервал periodi c в 5 секунд.
Старый добрый select()
используется для ожидания истечения таймера, а read()
используется для потребления данных (это число истекших тайм-аутов, игнорируем).
#include <stdio.h>
#include <sys/timerfd.h>
#include <sys/select.h>
#include <time.h>
int main()
{
int tfd = timerfd_create(CLOCK_REALTIME, 0);
printf("Starting at (%d)...\n", (int)time(NULL));
if(tfd > 0)
{
char dummybuf[8];
struct itimerspec spec =
{
{ 5, 0 }, // Set to {0, 0} if you need a one-shot timer
{ 4, 0 }
};
timerfd_settime(tfd, 0, &spec, NULL);
/* Wait */
fd_set rfds;
int retval;
/* Watch timefd file descriptor */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
FD_SET(tfd, &rfds);
/* Let's wait for initial timer expiration */
retval = select(tfd+1, &rfds, NULL, NULL, NULL); /* Last parameter = NULL --> wait forever */
printf("Expired at %d! (%d) (%d)\n", (int)time(NULL), retval, read(tfd, dummybuf, 8) );
/* Let's wait for initial timer expiration */
retval = select(tfd+1, &rfds, NULL, NULL, NULL);
printf("Expired at %d! (%d) (%d)\n", (int)time(NULL), retval, read(tfd, dummybuf, 8) );
retval = select(tfd+1, &rfds, NULL, NULL, NULL);
printf("Expired at %d! (%d) (%d)\n", (int)time(NULL), retval, read(tfd, dummybuf, 8) );
}
return 0;
}
И вот результат. Каждая строка также содержит метку времени, чтобы можно было проверить фактическое истекшее время>
Starting at (1596547762)...
Expired at 1596547766! (1) (8)
Expired at 1596547771! (1) (8)
Expired at 1596547776! (1) (8)
Обратите внимание:
- Мы только что выполнили 3 чтения для теста
- Интервалы: 4 с + 5 с + 5 с (начальный тайм-аут + два тайм-аута)
- 8 байт возвращаются
read()
. Мы проигнорировали их, но они содержали количество истекших тайм-аутов