условную переменную, чтобы уведомить главный поток об изменении. */
s = pthread_mutex_lock(&mtx);
if (s!= 0)
errExitEN(s, "pthread_mutex_lock");
expireCnt += 1 + timer_getoverrun(*tidptr);
s = pthread_mutex_unlock(&mtx);
if (s!= 0)
errExitEN(s, "pthread_mutex_unlock");
if (s!= 0)
errExitEN(s, "pthread_cond_signal");
}
int
main(int argc, char *argv[])
{
struct sigevent sev;
struct itimerspec ts;
timer_t *tidlist;
int s, j;
if (argc < 2)
usageErr("%s secs[/nsecs][: int-secs[/int-nsecs]]…\n", argv[0]);
tidlist = calloc(argc — 1, sizeof(timer_t));
if (tidlist == NULL)
errExit("malloc");
sev.sigev_notify_attributes = NULL;
/* Это мог бы быть указатель на структуру pthread_attr_t */
/* Создаем и запускаем по одному таймеру для каждого аргумента командной строки */
for (j = 0; j < argc — 1; j++) {
itimerspecFromStr(argv[j + 1], &ts);
/* Передается в виде аргумента функции threadFunc() */
errExit("timer_create");
printf("Timer ID: %ld (%s)\n", (long) tidlist[j], argv[j + 1]);
errExit("timer_settime");
}
/* Главный поток следит за условной переменной, которая оповещается при каждом
вызове функции уведомления. Мы выводим сообщение, чтобы пользователь знал
об этом событии. */
s = pthread_mutex_lock(&mtx);
if (s!= 0)
errExitEN(s, "pthread_mutex_lock");
s = pthread_cond_wait(&cond, &mtx);
if (s!= 0)
errExitEN(s, "pthread_cond_wait");
printf("main(): expireCnt = %d\n", expireCnt);
}
}
timers/ptmr_sigev_thread.c
Начиная с версии 2.6.25, ядро Linux предоставляет еще один программный интерфейс для создания таймеров, timerfd. Он позволяет создавать таймеры, уведомления о срабатывании которых можно прочитать из файлового дескриптора. Это может пригодиться, поскольку такой дескриптор можно отслеживать как и любой другой, используя вызовы select() и poll(), а также интерфейс epoll (см. главу 55).
При обращении к другим программным интерфейсам, описанным в данной главе, одновременное отслеживание одного или нескольких таймеров вместе с набором файловых дескрипторов требует определенных усилий.
Три новых системных вызова, входящих в этот программный интерфейс, по принципу своей работы аналогичны функциям timer_create(), timer_settime() и timer_gettime(), описанным в разделе 23.6.
Для начала рассмотрим системный вызов timerfd_create(), который создает новый объект таймера и возвращает ссылающийся на него файловый дескриптор.
#include
int timerfd_create(int
Возвращает файловый дескриптор при успешном завершении или –1, если произошла ошибка
Значение аргумента clockid может быть равно либо CLOCK_REALTIME, либо CLOCK_MONOTONIC (см. табл. 23.1).
В исходной реализации вызова timerfd_create() аргумент flags был зарезервирован на будущее и должен был быть равен 0. Но, начиная с Linux 2.6.27, он стал поддерживать два флага.
• TFD_CLOEXEC — устанавливает флаг FD_CLOEXEC для нового файлового дескриптора. Может быть полезен по тем же причинам, что и флаг O_CLOEXEC для вызова open(), описанный в подразделе 4.3.1.
• TFD_NONBLOCK — устанавливает исходному описанию открытого файла флаг O_NONBLOCK, делая будущие операции чтения неблокирующими. Это позволяет избежать дополнительного вызова fcntl(), который дает тот же результат.
Закончив использовать таймер, созданный с помощью вызова timerfd_create(), мы должны закрыть связанный с ним файловый дескриптор, чтобы ядро могло освободить его ресурсы.
Системный вызов позволяет запускать и останавливать таймер, на который ссылается файловый дескриптор fd.
#include
int timerfd_settime(int
struct itimerspec *
Возвращает 0 при успешном завершении или –1, если случилась ошибка
Аргумент new_value обозначает новые параметры таймера. Аргумент old_value может применяться для возвращения предыдущих параметров (подробности приводятся ниже, при описании вызова timerfd_gettime()). Если предыдущие параметры нас не интересуют, аргументу old_value можно присвоить NULL. Оба этих аргумента представляют собой структуры типа itimerspec, которые используются так же, как и в вызове timer_settime() (см. подраздел 23.6.2).
Аргумент flags аналогичен одноименному аргументу вызова timer_settime(). Он может быть равен либо 0 (в этом случае поле new_value.it_value интерпретируется относительно времени, полученного с помощью вызова timerfd_settime()), либо TFD_TIMER_ABSTIME (тогда new_value.it_value интерпретируется как абсолютное время, то есть отсчитывается с начальной позиции).