#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() для проверки его вручную.