Альтернатива epoll_wait, которая не ожидает файловый дескриптор?

#c #linux #file #epoll

#c #linux #файл #epoll

Вопрос:

У меня есть программа, которая создает таймер, используя timerfd_create (таймер, когда он истекает, устанавливает файловый дескриптор).

Проблема в том, что я использую epoll_wait для ожидания файлового дескриптора, затем проверяю срок действия с помощью fd=revent.data.fd и fd=timer_fd (см. Программу ниже).

Но если я сделаю это, epoll_wait моя программа заблокируется до истечения срока действия таймера, а я не хочу, чтобы это происходило .. я хочу, чтобы программа запускалась, и периодически я буду проверять, истек ли срок действия таймера. Есть ли какой-либо альтернативный подход к этому?

Пожалуйста, ознакомьтесь с программой ниже.

 enter code here
#include <sys/timerfd.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <time.h>

int main()
{
  struct itimerspec its;
  struct epoll_event event, revent;

  int timer_fd, efd, fd1, fd2;

 /* Setting timer interval */

 its.it_interval.tv_sec=1;
 its.it_interval.tv_nsec=0;

 /* Setting timer expiration */

 its.it_value.tv_sec=5;
 its.it_value.tv_nsec=0;

 efd=epoll_create(2);

 timer_fd=timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK);

 event.data.fd=timer_fd;
 event.events=EPOLLIN|EPOLLPRI;
 epoll_ctl(efd, EPOLL_CTL_ADD, timer_fd, amp;event);

 if(timer_fd==-1)
 {
  fprintf(stderr,"timerfd_settime error:");
  exit;
 }

if(timerfd_settime(timer_fd, 0, amp;its, NULL)==-1)
{
 fprintf(stderr,"timerfd_settime error:");
 exit;
}

printf("Starting the timer...");
fd1=epoll_wait(efd, amp;revent, 1, -1);

if(fd1<0) {
 fprintf(stderr, "epoll_wait errorn");
 exit;
}
else {

fprintf(stdout, "number of fds: %d",fd1);
}

fd2=revent.data.fd;

if(fd2==timer_fd) {
 printf("Timer expiredn");  

// IMPORTANT: This i want to check periodically without epoll_wait which blocks the program, What is the alternative?
}
  

}

Ответ №1:

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

 // set up timer
// ... 

uint64_t expirations;
if ((read(timer_fd, amp;expirations, sizeof(uint64_t))==-1) amp;amp; errno == EAGAIN) {
  printf("Timer has not expired yet.n");
} else {
  printf("Timer has expired %llu times.n", expirations);
}
  

Обратите внимание, что вам нужно будет инициализировать timer_fd с помощью флага TFD_NONBLOCK , иначе read будет заблокирован, если срок его действия еще не истек, а не сбой, но вы уже это делаете.

Комментарии:

1. @Sean: Почему uint64_t? Разве мы не можем напрямую использовать int?

2. Выдает ошибку timerfd1.c:59: error: 'for' loop initial declaration used outside C99 mode

3. На самом деле, нет. Чтение из timer_fd очень требовательно — оно завершится ошибкой EINVAL в любом случае, если вы предоставите ему буфер размером менее 8 байт.

4. Я не тестировал опубликованный мной код, поэтому он может не работать как есть, но ошибка, которую вы опубликовали, похоже, не из-за этого. Есть ли у вас что-нибудь подобное for(int i = 0; i < n, i ) где-нибудь? В старом добром C вы не можете этого сделать, вы должны сделать int i; for (i = 0; i < n; i )

5. @Sean: О да, большое спасибо … причина была та же .. также ваш код сработал, большое вам спасибо 🙂

Ответ №2:

Это кажется довольно обратным. Причина, по которой timerfd был создан в первую очередь, заключалась в том, чтобы разрешить опрос fd для завершения таймера вместо использования сигналов / потоков / {без уведомления}, как позволяет обычный интерфейс timer_create. Если вы не хотите проводить опрос по fd, не используйте timerfd_create!

Итак, если вы хотите периодически опрашивать свой таймер самостоятельно, просто используйте timer_create() для создания таймера с SIGEV_NONE, а затем используйте timer_gettime() для проверки его вручную.