linux定时器timerfd系列函数学习

本文介绍了Linux中的timerfd函数,包括timerfd_create、timerfd_settime和timerfd_gettime等,阐述了其在结合epoll等机制处理定时事件的优势。详细讲解了各参数含义,并提供了一个测试程序示例,演示了如何设置和读取定时器的超时事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用timerfd的好处是可以结合epoll或poll或select使用,当超时时间到时epoll等会返回可读。

1.

int timerfd_create(int clockid,int flags)

timerfd_create返回一个文件描述符,该文件描述符和定时器所关联。

clockid:

clockid可以为CLOCK_REALTIME或者CLOCK_MONOTONIC。最好使用CLOCK_MONOTONIC,这样的话即使你改变了系统时钟的话也不会受到影响,但是CLOCK_REALTIME会受到硬性。如果对这两个选项感兴趣的话可以自行去网上查写关于他们的资料。

flags:

flags可以是TFD_NONBLOCK、TFD_CLOEXEC的或。设置TFD_NONBLOCK代表把返回的文件描述符设置为非阻塞模式,这个和用fcntl设置该文件描述符的O_NONBLOCK的效果一样。设置TFP_CLOEXEC代表当执行exec时该文件描述符会自动关闭。

 

2.

int timerfd_settime(int fd,int flags,const struct itimerspec *new_value,struct itimerspec *old_value)

timerfd_settime可以启动或者停止定时器。

让我们先看看两个结构体:

                         struct timespec{

                                time_t  tv_sec;//秒数

                                long tv_nsec;//纳秒数

                       }

                      struct itimerspec{

                               struct timespec it_interval;

                               struct timespec it_value;

                     }

参数说明:

new_value.it_value:设置初始定时器时间。只要new_value.it_value中的tv_sec和tv_nsec有一个不为0,则启动定时器。把new_value.it_value中的tv_sec和tv_nsec都设为0,则停止定时器。(视flags而定,如果flags是0那么new_value.it_value就是相对值,如果flags是TFD_TIMER_ABSTIME,那么new_value.it_value就是绝对时间)

new_value.it_interval:设置定时时间间隔(定时器可以一直定时)。只要new_value.it_interval中的tv_sec和tv_nsec有一个不为0,那么就会在第一次超时之后把定时时间设为这个值。如果把tv_sec和tv_nsec都设为0,那么定时器只会定时一次,不会重复定时。(new_value.it_interval总是设置为相对时间)

flags:flags参数为0,表示启动相对计时器(new_value.it_value指定相对定时时间), TFD_TIMER_ABSTIME用于启动绝对定时器(当时钟的值达到new_value中指定的值时,定时器将到期)。

old_value.it_value:表示上一次设置的定时器还有多久就到时间了(返回相对时间,不管flags设置成什么)

old_value.it_interval:返回上一次设置的值(总是返回相对时间)

 

3.

int timerfd_gettime(int fd,struct itimerspec *curr_value);

参数:

curr_value:返回还有多久定时器要到期,以及当前设置的循环定时周期。如果it_value中的中的tv_sec和tv_nsec都为0,那么表示定时器已经停止了。curr_value->it_interval返回当前甚至的循环定时周期,如果it_value中的中的tv_sec和tv_nsec都为0,表示该定时器只定时一次,不会循环定时(it_value和it_interval返回的总是相对值)

 

4.read的返回值

read(timerfd,buf,sizeof(buf));   buf应该是uint64_t。如果有超时时间发生,则从buf返回超时的次数。

1.如果没有设定O_NONBLOCK,则read阻塞,知道下一次超时时间到来。

2.如果设定了O_NONBLOCK,且没有超时时间发生,则置error为EAGAIN

3.如果buf的大小小于8个字节,那么read置error为EINVAL

 

 

 

 

下面附上一段测试程序:第一个参数为第一次超时什么时候发生,第二个参数为超时间隔设为多少,第三个参数为你想要发生多少次超时时间。程序可以在man timerfd_create的最后面找到。

#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)

static void print_elapsed_time(void)
{
      static struct timespec start;
      struct timespec curr;
      static int first_call = 1;
      int secs, nsecs;

      if (first_call) {
          first_call = 0;
          if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
              handle_error("clock_gettime");
      }

      if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)
          handle_error("clock_gettime");

          secs = curr.tv_sec - start.tv_sec;
          nsecs = curr.tv_nsec - start.tv_nsec;
          if (nsecs < 0) {
              secs--;
              nsecs += 1000000000;
          }
          printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000);
      }

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 ((argc != 2) && (argc != 4)) {
               fprintf(stderr, "%s init-secs [interval-secs max-exp]\n",
                       argv[0]);
               exit(EXIT_FAILURE);
           }

           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 + atoi(argv[1]);
           new_value.it_value.tv_nsec = now.tv_nsec;
           if (argc == 2) {
               new_value.it_interval.tv_sec = 0;
               max_exp = 1;
           } else {
               new_value.it_interval.tv_sec = atoi(argv[2]);
               max_exp = atoi(argv[3]);
           }
           new_value.it_interval.tv_nsec = 20;

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

      
       struct itimerspec old_value;
           if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, &old_value) == -1)
               handle_error("timerfd_settime");
      
           print_elapsed_time();
           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;
               print_elapsed_time();
               printf("read: %llu; total=%llu\n",
                       (unsigned long long) exp,
                       (unsigned long long) tot_exp);
           }

           exit(EXIT_SUCCESS);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值