c-如何正确使用timerfd



我将timerfd与zmq一起使用。

如何使用timerfd_createtimerfd_set等待计时器一秒钟(https://man7.org/linux/man-pages/man2/timerfd_create.2.html)?

我已经浏览了这个链接,但我仍然不知道如何初始化一个计时器,该计时器在创建和设置时每个刻度等待一秒钟。这正是我的任务:

我们用timerfd_create()启动计时器,它是每秒1次。使用计时器_set_(..)设置计时器时计数器只是简单地递增,它随每个刻度递减。当计数器达到0时,计时器已过期。

在这个项目中,我们有一个函数计时器_ set _(),其中计时器是用函数timerfd_create和timerfd_settimer()设置的。我希望你能帮助我。

这是我的进展(我的代码的一部分(:

struct itimerspec timerValue;
g_items[n].socket = nullptr; 
g_items[n].events = ZMQ_POLLIN;
g_items[n].fd = timerfd_create(CLOCK_REALTIME, 0);
if(g_items[n].fd == -1 ){
printf("timerfd_create() failed: errno=%dn", errno);
return -1;
}  
timerValue.it_value.tv_sec = 1;
timerValue.it_value.tv_nsec = 0;
timerValue.it_interval.tv_sec = 1;
timerValue.it_interval.tv_nsec = 0;
timerfd_settime(g_items[n].fd,  0, &timerValue, NULL); 

出现了关于正确设置计时器超时的问题。

使用设置

timerValue.it_value.tv_sec = 1;
timerValue.it_value.tv_nsec = 0;
timerValue.it_interval.tv_sec = 1;
timerValue.it_interval.tv_nsec = 0;

您将初始超时正确设置为1s(字段timerValue.it_value(。但你也设置了的周期性间隔为1,你没有提到这样做的意愿。


关于超时

本手册的以下段落描述了这种行为:

int timerfd_create(int clockid, int flags);

new_value.it_value指定计时器的初始过期时间,以秒和纳秒为单位。将new_value.it_value的任何一个字段设置为非零值将启用计时器
new_value.it_value的两个字段都设置为零将解除计时器的武装

new_value.it_interval的一个或两个字段设置为非零值可指定初始过期后重复计时器过期的周期(以秒和纳秒为单位(如果new_value.it_interval的两个字段都为零,则计时器仅在new_value.it_value指定的时间过期一次

最后一段的重点是我的,因为它展示了如何使用单次计时器。


timerrfd的优点。如何检测计时器过期

timerfd提供的主要优点是定时器与文件描述符相关联,这意味着它是

可以由select(2(、poll(2(和epoll(7(进行监控。

关于read()的另一个答案中包含的信息也是有效的:假设即使使用select()等函数,也需要read()函数才能使用文件描述符中的数据。


一个完整的例子

在下面的演示程序中,设置了4秒的超时;之后设置5秒的周期性间隔。

好的旧select()用于等待计时器过期,而read()用于消耗数据(即过期超时的数量;我们将忽略它(。

#include <stdio.h>
#include <sys/timerfd.h>
#include <sys/select.h>
#include <time.h>
int main()
{
int tfd = timerfd_create(CLOCK_REALTIME,  0);

printf("Starting at (%d)...n", (int)time(NULL));

if(tfd > 0)
{
char dummybuf[8];
struct itimerspec spec =
{
{ 5, 0 }, // Set to {0, 0} if you need a one-shot timer
{ 4, 0 }
};
timerfd_settime(tfd, 0, &spec, NULL);
/* Wait */
fd_set rfds;
int retval;
/* Watch timefd file descriptor */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
FD_SET(tfd, &rfds);
/* Let's wait for initial timer expiration */
retval = select(tfd+1, &rfds, NULL, NULL, NULL); /* Last parameter = NULL --> wait forever */
printf("Expired at %d! (%d) (%d)n", (int)time(NULL), retval, read(tfd, dummybuf, 8) );

/* Let's wait (twice) for periodic timer expiration */
retval = select(tfd+1, &rfds, NULL, NULL, NULL);
printf("Expired at %d! (%d) (%d)n", (int)time(NULL), retval, read(tfd, dummybuf, 8) );
retval = select(tfd+1, &rfds, NULL, NULL, NULL);
printf("Expired at %d! (%d) (%d)n", (int)time(NULL), retval, read(tfd, dummybuf, 8) );
}

return 0;
}

这里是输出。每一行还包含时间戳,以便可以检查实际经过的时间>

Starting at (1596547762)...
Expired at 1596547766! (1) (8)
Expired at 1596547771! (1) (8)
Expired at 1596547776! (1) (8)

请注意:

  • 我们刚刚进行了3次读取,用于测试
  • 间隔为4s+5s+5s(初始超时+两次间隔超时(
  • CCD_ 26返回8个字节。我们忽略了它们,但它们包含过期超时的数量

使用timerfds,其思想是fd上的read将返回计时器过期的次数。

timerfd_settime(2(手册页:

对计时器文件描述符进行操作timerfd_create((返回的文件描述符支持以下操作:

读取(2(如果计时器自上次使用修改其设置以来已过期一次或多次timerfd_settime((,或者自上次成功读取(2(以来,则指定给读取(2一个无符号的8字节整数(uint64_t(,包含已发生的过期次数。

如果在读取(2(时没有发生定时器过期,则调用将阻止直到下一个计时器到期,或者如果文件描述符已经使得非阻塞(通过使用fcntl(2(F_SETFL操作来设置O_NONBLOCK标志(。

因此,基本上,您创建一个无符号的8字节整数(在Linux上为uint64_t(,并将其传递给您的读取调用。

uint64_t buf;
int expired = read( g_items[n].fd, &buf, sizeof(uint64_t));
if( expired < 0 ) perror("read");

类似的东西,如果你想阻止直到到期。

最新更新