timerfd是Linux为用户程序提供的一个定时器接口。这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,所以能够被用于select/poll的应用场景。timerfd是linux内核2.6.25版本中加入的借口。
timerfd、eventfd、signalfd配合epoll使用,可以构造出一个零轮询的程序,但程序没有处理的事件时,程序是被阻塞的。这样的话在某些移动设备上程序更省电。

clock_gettime函数可以获取系统时钟,精确到纳秒。需要在编译时指定库:-lrt。可以获取两种类型事件:
CLOCK_REALTIME:相对时间,从1970.1.1到目前的时间。更改系统时间会更改获取的值。也就是,它以系统时间为坐标。
CLOCK_MONOTONIC:与CLOCK_REALTIME相反,它是以绝对时间为准,获取的时间为系统重启到现在的时间,更改系统时间对齐没有影响。

timerfd_create:
生成一个定时器对象,返回与之关联的文件描述符。接收两个入参,一个是clockid,填写CLOCK_REALTIME或者CLOCK_MONOTONIC,参数意义同上。第二个可以传递控制标志:TFD_NONBLOCK(非阻塞),TFD_CLOEXEC(同O_CLOEXEC)

注:timerfd的进度要比usleep要高。

timerfd_settime:能够启动和停止定时器;可以设置第二个参数:flags,0表示是相对定时器,TFD_TIMER_ABSTIME表示是绝对定时器。
第三个参数设置超时时间,如果为0则表示停止定时器。定时器设置超时方法:
1、设置超时时间是需要调用clock_gettime获取当前时间,如果是绝对定时器,那么需要获取CLOCK_REALTIME,在加上要超时的时间。如果是相对定时器,要获取CLOCK_MONOTONIC时间。
2、数据结构: 
   struct timespec {
               time_t tv_sec;                /* Seconds */
               long   tv_nsec;               /* Nanoseconds */
           };

struct itimerspec {
               struct timespec it_interval;  /* Interval for periodic timer */
               struct timespec it_value;     /* Initial expiration */
           };
      it_value是首次超时时间,需要填写从clock_gettime获取的时间,并加上要超时的时间。 it_interval是后续周期性超时时间,是多少时间就填写多少。
     注意一个容易犯错的地方:tv_nsec加上去后一定要判断是否超出1000000000(如果超过要秒加一),否则会设置失败。
     
     it_interval不为0则表示是周期性定时器。
     it_value和it_interval都为0表示停止定时器。

注:timerfd_create第一个参数和clock_gettime的第一个参数都是CLOCK_REALTIME或者CLOCK_MONOTONIC,timerfd_settime的第二个参数为0(相对定时器)或者TFD_TIMER_ABSTIME,三者的关系:
1、如果timerfd_settime设置为TFD_TIMER_ABSTIME(决定时间),则后面的时间必须用clock_gettime来获取,获取时设置CLOCK_REALTIME还是CLOCK_MONOTONIC取决于timerfd_create设置的值。
2、如果timerfd_settime设置为0(相对定时器),则后面的时间必须用相对时间,就是:
    new_value.it_value.tv_nsec = 500000000;
    new_value.it_value.tv_sec = 3;
    new_value.it_interval.tv_sec = 0;
    new_value.it_interval.tv_nsec = 10000000;

read函数可以读timerfd,读的内容为uint_64,表示超时次数。

timerfd简单的性能测试:
申请1000个定时器,超时间定位1s,每秒超时一次,发现cpu占用率在3.0G的cpu上大概为1%,10000个定时器的话再7%左右,而且不会出现同时超时两个的情况,如果有printf到前台,则一般会出现定时器超时多次(3-5)才回调。

关于timerfd的一个简单测试程序:

(1)timerfd_create()函数

#include <sys/timerfd.h>int timerfd_create(int clockid, int flags);
/*
timerfd_create()函数创建一个定时器对象,同时返回一个与之关联的文件描述符。
clockid:clockid标识指定的时钟计数器,可选值(CLOCK_REALTIME、CLOCK_MONOTONIC。。。)
CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,中间时刻如果系统时间被用户改成其他,则对应的时间相应改变
CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响
flags:参数flags(TFD_NONBLOCK(非阻塞模式)/TFD_CLOEXEC(表示当程序执行exec函数时本fd将被系统自动关闭,表示不传递)
*/

(2)timerfd_settime()函数

 1 #include <sys/timerfd.h>2 3 struct timespec {4     time_t tv_sec;                /* Seconds */5     long   tv_nsec;               /* Nanoseconds */6 };7 8 struct itimerspec {9     struct timespec it_interval;  /* Interval for periodic timer (定时间隔周期)*/
10     struct timespec it_value;     /* Initial expiration (第一次超时时间)*/
11 };
12 int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
13 /*
14     timerfd_settime()此函数用于设置新的超时时间,并开始计时,能够启动和停止定时器;
15     fd: 参数fd是timerfd_create函数返回的文件句柄
16     flags:参数flags为1代表设置的是绝对时间(TFD_TIMER_ABSTIME 表示绝对定时器);为0代表相对时间。
17     new_value: 参数new_value指定定时器的超时时间以及超时间隔时间
18     old_value: 如果old_value不为NULL, old_vlaue返回之前定时器设置的超时时间,具体参考timerfd_gettime()函数
19
20     ** it_interval不为0则表示是周期性定时器。
21        it_value和it_interval都为0表示停止定时器
22 */

(3)timerfd_gettime()函数

1 int timerfd_gettime(int fd, struct itimerspec *curr_value);
2 /*
3     timerfd_gettime()函数获取距离下次超时剩余的时间
4     curr_value.it_value 字段表示距离下次超时的时间,如果改值为0,表示计时器已经解除
5     改字段表示的值永远是一个相对值,无论TFD_TIMER_ABSTIME是否被设置
6     curr_value.it_interval 定时器间隔时间
7 */

1 uint64_t exp = 0;
2 read(fd, &exp, sizeof(uint64_t));
3 //可以用read函数读取计时器的超时次数,改值是一个8字节无符号的长整型

(4)下面贴出一个timerfd配合epoll函数的简单例子

  1 /********************************************************2 * Filename: timerfd.c3 * Author: zhangwj4 * Desprition: a sample program of timerfd5 * Date: 2017-04-176 * Warnning:7 ********************************************************/8 #include <stdio.h>9 #include <stdint.h>10 #include <string.h>11 #include <stdlib.h>12 #include <pthread.h>13 #include <errno.h>14 #include <sys/epoll.h>15 #include <sys/timerfd.h>16 17 #if 018 struct timespec {19     time_t tv_sec;                /* Seconds */20     long   tv_nsec;               /* Nanoseconds */21 };22 23 struct itimerspec {24     struct timespec it_interval;  /* Interval for periodic timer */25     struct timespec it_value;     /* Initial expiration */26 };27 #endif28 29 #define EPOLL_LISTEN_CNT        25630 #define EPOLL_LISTEN_TIMEOUT    50031 32 #define LOG_DEBUG_ON 133 34 #ifdef LOG_DEBUG_ON 35 #define LOG_DEBUG(fmt, args...) \36     do {  \37         printf("[DEBUG]:");\38         printf(fmt "\n", ##args); \39     } while(0);40 #define LOG_INFO(fmt, args...) \41     do { \42         printf("[INFO]:");\43         printf(fmt "\n", ##args); \44     } while(0);45 #define LOG_WARNING(fmt, args...) \46     do { \47         printf("[WARNING]:");\48         printf(fmt "\n", ##args); \49     } while(0);50 #else51 #define LOG_DEBUG(fmt, args...) 52 #define LOG_INFO(fmt, args...) 53 #define LOG_WARNING(fmt, args...) 54 #endif55 #define LOG_ERROR(fmt, args...) \56     do{ \57         printf("[ERROR]:");\58         printf(fmt "\n", ##args);\59     }while(0);60 61 #define handle_error(msg) \62         do { perror(msg); exit(EXIT_FAILURE); } while (0)63 64 static int g_epollfd = -1;65 static int g_timerfd = -1;66 uint64_t tot_exp = 0;67 68 static void help(void)69 {70     exit(0);71 }72 73 static void print_elapsed_time(void)74 {75     static struct timespec start;76     struct timespec curr;77     static int first_call = 1;78     int secs, nsecs;79     80     if (first_call) {81         first_call = 0;82         if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) 83             handle_error("clock_gettime");84     }   85     86     if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1) 87         handle_error("clock_gettime");88     89     secs = curr.tv_sec - start.tv_sec;90     nsecs = curr.tv_nsec - start.tv_nsec;91     if (nsecs < 0) {92         secs--;93         nsecs += 1000000000;94     }   95     printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000);96 }97 98 void timerfd_handler(int fd)99 {
100     uint64_t exp = 0;
101
102     read(fd, &exp, sizeof(uint64_t));
103     tot_exp += exp;
104     print_elapsed_time();
105     printf("read: %llu, total: %llu\n", (unsigned long long)exp, (unsigned long long)tot_exp);
106
107     return;
108 }
109
110 void epoll_event_handle(void)
111 {
112     int i = 0;
113     int fd_cnt = 0;
114     int sfd;
115     struct epoll_event events[EPOLL_LISTEN_CNT];
116
117     memset(events, 0, sizeof(events));
118     while(1)
119     {
120         /* wait epoll event */
121         fd_cnt = epoll_wait(g_epollfd, events, EPOLL_LISTEN_CNT, EPOLL_LISTEN_TIMEOUT);
122         for(i = 0; i < fd_cnt; i++)
123         {
124             sfd = events[i].data.fd;
125             if(events[i].events & EPOLLIN)
126             {
127                 if (sfd == g_timerfd)
128                 {
129                     timerfd_handler(sfd);
130                 }
131             }
132         }
133     }
134 }
135
136 int epoll_add_fd(int fd)
137 {
138     int ret;
139     struct epoll_event event;
140
141     memset(&event, 0, sizeof(event));
142     event.data.fd = fd;
143     event.events = EPOLLIN | EPOLLET;
144
145     ret = epoll_ctl(g_epollfd, EPOLL_CTL_ADD, fd, &event);
146     if(ret < 0) {
147         LOG_ERROR("epoll_ctl Add fd:%d error, Error:[%d:%s]", fd, errno, strerror(errno));
148         return -1;
149     }
150
151     LOG_DEBUG("epoll add fd:%d--->%d success", fd, g_epollfd);
152     return 0;
153 }
154
155 int epollfd_init()
156 {
157     int epfd;
158
159     /* create epoll fd */
160     epfd = epoll_create(EPOLL_LISTEN_CNT);
161     if (epfd < 0) {
162         LOG_ERROR("epoll_create error, Error:[%d:%s]", errno, strerror(errno));
163         return -1;
164     }
165     g_epollfd = epfd;
166     LOG_DEBUG("epoll fd:%d create success", epfd);
167
168     return epfd;
169 }
170
171 int timerfd_init()
172 {
173     int tmfd;
174     int ret;
175     struct itimerspec new_value;
176
177     new_value.it_value.tv_sec = 2;
178     new_value.it_value.tv_nsec = 0;
179     new_value.it_interval.tv_sec = 1;
180     new_value.it_interval.tv_nsec = 0;
181
182     tmfd = timerfd_create(CLOCK_MONOTONIC, 0);
183     if (tmfd < 0) {
184         LOG_ERROR("timerfd_create error, Error:[%d:%s]", errno, strerror(errno));
185         return -1;
186     }
187
188     ret = timerfd_settime(tmfd, 0, &new_value, NULL);
189     if (ret < 0) {
190         LOG_ERROR("timerfd_settime error, Error:[%d:%s]", errno, strerror(errno));
191         close(tmfd);
192         return -1;
193     }
194
195     if (epoll_add_fd(tmfd)) {
196         close(tmfd);
197         return -1;
198     }
199     g_timerfd = tmfd;
200
201     return 0;
202 }
203
204 int main(int argc, char **argv)
205 {
206     if (epollfd_init() < 0) {
207         return -1;
208     }
209
210     if (timerfd_init()) {
211         return -1;
212     }
213
214     /* event handle */
215     epoll_event_handle();
216
217     return 0;
218 }

原文链接:https://blog.csdn.net/chgaowei/article/details/21295811

linux下的timerfd机制相关推荐

  1. 2017-2018-1 20155222 《信息安全系统设计基础》第10周 Linux下的IPC机制

    2017-2018-1 20155222 <信息安全系统设计基础>第10周 Linux下的IPC机制 IPC机制 在linux下的多个进程间的通信机制叫做IPC(Inter-Process ...

  2. linux下的缓存机制及清理buffer/cache/swap的方法梳理

    1)缓存机制介绍 在Linux系统中,为了提高文件系统性能,内核利用一部分物理内存分配出缓冲区,用于缓存系统操作和数据文件,当内核收到读写的请求时,内核先去缓存区找是否有请求的数据,有就直接返回,如果 ...

  3. linux从a自增10_C语言程序前后自增(++a、a++)在Linux下的实现机制

    看到一道"经典Linux C"面试题,关于左值和右值的. 华为笔试题 1.写出判断ABCD四个表达式的是否正确, 若正确, 写出经过表达式中 a的值(3分) int a = 4; ...

  4. linux下的rtc机制

    Linux的RTC驱动相对还是比较简单的,可以将它作为一个普通的字符型设备,或者一个misc设备,也可以是一个平台设备,这都没有关系,主要还是对rtc_ops这个文件操作结构体中的成员填充,这里主要涉 ...

  5. Linux下的UDEV机制 / 守护进程

    一.Udev概念引入 udev是一个设备管理工具,udev以守护进程的形式运行,通过 侦听内核发出来的uevent来管 理 /dev目录下的设备文件. udev在 用户空间运行,而 不在内核空间 运行 ...

  6. 从一道面试题谈linux下fork的运行机制

    http://kb.cnblogs.com/page/76622/ 今天一位朋友去一个不错的外企面试linux开发职位,面试官出了一个如下的题目: 给出如下C程序,在linux下使用gcc编译: #i ...

  7. 机制 linux_从一道面试题谈linux下fork的运行机制

    今天一位朋友去一个不错的外企面试linux开发职位,面试官出了一个如下的题目: 给出如下C程序,在linux下使用gcc编译: #include "stdio.h" #includ ...

  8. LINUX下FORK的运行机制详细解析

    摘要:由于fork函数运行机制的复杂性,造就了当两个fork并排时,问题就变得很复杂.解这个题的关键,一是要对linux下进程的机制有一定认识,二是抓住上文提到的几个关于fork的关键点. 今天一位朋 ...

  9. linux 进程 读写锁,linux 下实现高性能读写锁(read/write lock)

    前一篇文章分析了Windows slim read/write lock的工作原理.我们知道它的设计相当精妙,于是我们可以借鉴它的思路来设计linux下的读写锁. 在这个读写锁的设计上,需要注意的是l ...

  10. Linux下堆漏洞利用(off-by-one)

    一个字节溢出被称为off-by-one,曾经的一段时间里,off-by-one被认为是不可以利用的,但是后来研究发现在堆上哪怕只有一个字节的溢出也会导致任意代码的执行.同时堆的off-by-one利用 ...

最新文章

  1. SAP MM 由于没有维护Plant的Address信息导致不能在ME51N和ME21N界面里输入工厂代码
  2. modules not found(模块未找到)的解决方案
  3. Windows 服务全攻略(1)
  4. 选择排序算法,只需这篇文章就够了
  5. SAP Cloud for Customer Business Configuration的权限控制
  6. 日本研发高精度诊疗感应器,或颠覆疾病诊疗
  7. 去除input填充颜色
  8. cuda event
  9. Is there anyway to discover which ip addresses are connected to the db?
  10. E-BERT: 电商领域语言模型优化实践
  11. Linux源码安装pgadmin4,linux安装pgadmin3
  12. 如何监控网页卡顿和崩溃?
  13. 10分钟搭建linux代理服务器
  14. Python3使用dbf模块读写dbf文件
  15. 无线测温系统在高低压开关柜内的运行---安科瑞 顾城
  16. JS打印表格时边框缺失问题
  17. 时空旅行的可能性(无聊研究社)
  18. 艺赛旗RPA8.0-用户体验提升抢先看(一)
  19. 说说如何在项目中引入 jBPM4 工作流框架以及遇到的坑儿
  20. 因子分析 二元logistic回归

热门文章

  1. 如何在线制作ico图标,自己动手丰衣足食
  2. js 日历,节假日,添加日志
  3. 怎样在mac系统里将文件拷贝到移动硬盘教程
  4. C++面向对象小练习:几何图形类
  5. Vista系统Administrator帐户的激活与禁用
  6. Java学习之基础知识2
  7. excel教程自学网_收藏!这37个自学网站,一年让你省下十几万
  8. 服装企业二维码应用现状,如何建立二维码营销平台规则体系?
  9. 对话王劲:无人驾驶每天能救500多条人命 | AI英雄
  10. 60万餐厅数据为你画出全国美食地图(附技术讲解)