условную переменную, чтобы уведомить главный поток об изменении. */

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");

s = pthread_cond_signal(&cond);

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 = SIGEV_THREAD; /* Уведомляем с помощью потока */

sev.sigev_notify_function = threadFunc; /* Начальная функция потока */

sev.sigev_notify_attributes = NULL;

/* Это мог бы быть указатель на структуру pthread_attr_t */

/* Создаем и запускаем по одному таймеру для каждого аргумента командной строки */

for (j = 0; j < argc — 1; j++) {

itimerspecFromStr(argv[j + 1], &ts);

 sev.sigev_value.sival_ptr = &tidlist[j];

/* Передается в виде аргумента функции threadFunc() */

 if (timer_create(CLOCK_REALTIME, &sev, &tidlist[j]) == –1)

errExit("timer_create");

printf("Timer ID: %ld (%s)\n", (long) tidlist[j], argv[j + 1]);

 if (timer_settime(tidlist[j], 0, &ts, NULL) == –1)

errExit("timer_settime");

}

/* Главный поток следит за условной переменной, которая оповещается при каждом

вызове функции уведомления. Мы выводим сообщение, чтобы пользователь знал

об этом событии. */

s = pthread_mutex_lock(&mtx);

if (s!= 0)

errExitEN(s, "pthread_mutex_lock");

for (;;) {

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

23.7. Таймеры, которые уведомляют с помощью файловых дескрипторов: интерфейс timerfd

Начиная с версии 2.6.25, ядро Linux предоставляет еще один программный интерфейс для создания таймеров, timerfd. Он позволяет создавать таймеры, уведомления о срабатывании которых можно прочитать из файлового дескриптора. Это может пригодиться, поскольку такой дескриптор можно отслеживать как и любой другой, используя вызовы select() и poll(), а также интерфейс epoll (см. главу 55).

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

Три новых системных вызова, входящих в этот программный интерфейс, по принципу своей работы аналогичны функциям timer_create(), timer_settime() и timer_gettime(), описанным в разделе 23.6.

Для начала рассмотрим системный вызов timerfd_create(), который создает новый объект таймера и возвращает ссылающийся на него файловый дескриптор.

#include

int timerfd_create(int clockid, int flags);

Возвращает файловый дескриптор при успешном завершении или –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 fd, int flags, const struct itimerspec *new_value,

struct itimerspec *old_value);

Возвращает 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 интерпретируется как абсолютное время, то есть отсчитывается с начальной позиции).

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

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