需要每X(例如5)秒调用一个函数,下面的代码就是这样做的。但它阻止了代码的执行。因为我希望它像setitimer一样工作,我可以说每5秒调用一次函数并做其他事情。感谢
#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h> /* Definition of uint64_t */
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
struct itimerspec new_value;
int max_exp, fd;
struct timespec now;
uint64_t exp, tot_exp;
ssize_t s;
if (clock_gettime(CLOCK_REALTIME, &now) == -1)
handle_error("clock_gettime");
/* Create a CLOCK_REALTIME absolute timer with initial
expiration and interval as specified in command line */
new_value.it_value.tv_sec = now.tv_sec + 1;
new_value.it_value.tv_nsec = now.tv_nsec;
new_value.it_interval.tv_sec = 5;
new_value.it_interval.tv_nsec = 0;
max_exp = 5; //say 5 times
fd = timerfd_create(CLOCK_REALTIME, 0);
if (fd == -1)
handle_error("timerfd_create");
if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)
handle_error("timerfd_settime");
printf("timer started\n");
for (tot_exp = 0; tot_exp < max_exp;) {
s = read(fd, &exp, sizeof(uint64_t));
if (s != sizeof(uint64_t))
handle_error("read");
tot_exp += exp;
printf("read: %llu; total=%llu\n",
(unsigned long long) exp,
(unsigned long long) tot_exp);
}
//Do something else ?
//while(1);
exit(EXIT_SUCCESS);
}
修改 我还有一个问题。 在上面的代码中更改这些行
new_value.it_interval.tv_sec = 5;
new_value.it_interval.tv_nsec = 0;
到
new_value.it_interval.tv_sec = 0;
new_value.it_interval.tv_nsec = 5000000000;
我看到没有5秒的延迟,这里发生了什么?
答案 0 :(得分:2)
您需要了解如何使用多路复用系统调用(如poll(2)(或较旧的select(2)
,这些系统往往会过时)并使用它们来测试{{3}获取的文件描述符的可读性} read(2)
之前 -
但是,请注意timerfd_create
仅在read
调用成功时才有效。因此,只有当poll
告诉您fd不可读时,您才能做其他事情。其他东西应该很快(持续不到5秒)。
您可能想要调查事件循环库,例如timerfd_create(2)(包裹poll
)。如果您正在编写图形应用程序(使用Qt或Gtk),它已经拥有自己的事件循环。如果足够聪明,您可以在没有任何timerfd_create
的情况下执行5秒的时间段,只需通过事件循环(通过仔细设置给予poll
的超时等)。
tv_nsec
字段应始终为非负数且小于1000000000(一秒内的纳秒数)。
答案 1 :(得分:0)
你有什么理由要使用timerfd吗?只需安排一个警报并为SIGALRM设置一个处理程序来调用你的函数。
如果您不想使用信号,只需创建一个额外的线程来阻止您的计时器fd并在主线程中正常进行。
如果您不喜欢其中任何一种,并且想要在等待期间继续工作,则必须进行轮询。您可以像basile建议的那样进行操作,或者您可以只存储当前时间并检查您何时进行轮询以查看是否已经过了所需的时间段。