linux下的timerfd机制
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机制相关推荐
- 2017-2018-1 20155222 《信息安全系统设计基础》第10周 Linux下的IPC机制
2017-2018-1 20155222 <信息安全系统设计基础>第10周 Linux下的IPC机制 IPC机制 在linux下的多个进程间的通信机制叫做IPC(Inter-Process ...
- linux下的缓存机制及清理buffer/cache/swap的方法梳理
1)缓存机制介绍 在Linux系统中,为了提高文件系统性能,内核利用一部分物理内存分配出缓冲区,用于缓存系统操作和数据文件,当内核收到读写的请求时,内核先去缓存区找是否有请求的数据,有就直接返回,如果 ...
- linux从a自增10_C语言程序前后自增(++a、a++)在Linux下的实现机制
看到一道"经典Linux C"面试题,关于左值和右值的. 华为笔试题 1.写出判断ABCD四个表达式的是否正确, 若正确, 写出经过表达式中 a的值(3分) int a = 4; ...
- linux下的rtc机制
Linux的RTC驱动相对还是比较简单的,可以将它作为一个普通的字符型设备,或者一个misc设备,也可以是一个平台设备,这都没有关系,主要还是对rtc_ops这个文件操作结构体中的成员填充,这里主要涉 ...
- Linux下的UDEV机制 / 守护进程
一.Udev概念引入 udev是一个设备管理工具,udev以守护进程的形式运行,通过 侦听内核发出来的uevent来管 理 /dev目录下的设备文件. udev在 用户空间运行,而 不在内核空间 运行 ...
- 从一道面试题谈linux下fork的运行机制
http://kb.cnblogs.com/page/76622/ 今天一位朋友去一个不错的外企面试linux开发职位,面试官出了一个如下的题目: 给出如下C程序,在linux下使用gcc编译: #i ...
- 机制 linux_从一道面试题谈linux下fork的运行机制
今天一位朋友去一个不错的外企面试linux开发职位,面试官出了一个如下的题目: 给出如下C程序,在linux下使用gcc编译: #include "stdio.h" #includ ...
- LINUX下FORK的运行机制详细解析
摘要:由于fork函数运行机制的复杂性,造就了当两个fork并排时,问题就变得很复杂.解这个题的关键,一是要对linux下进程的机制有一定认识,二是抓住上文提到的几个关于fork的关键点. 今天一位朋 ...
- linux 进程 读写锁,linux 下实现高性能读写锁(read/write lock)
前一篇文章分析了Windows slim read/write lock的工作原理.我们知道它的设计相当精妙,于是我们可以借鉴它的思路来设计linux下的读写锁. 在这个读写锁的设计上,需要注意的是l ...
- Linux下堆漏洞利用(off-by-one)
一个字节溢出被称为off-by-one,曾经的一段时间里,off-by-one被认为是不可以利用的,但是后来研究发现在堆上哪怕只有一个字节的溢出也会导致任意代码的执行.同时堆的off-by-one利用 ...
最新文章
- SAP MM 由于没有维护Plant的Address信息导致不能在ME51N和ME21N界面里输入工厂代码
- modules not found(模块未找到)的解决方案
- Windows 服务全攻略(1)
- 选择排序算法,只需这篇文章就够了
- SAP Cloud for Customer Business Configuration的权限控制
- 日本研发高精度诊疗感应器,或颠覆疾病诊疗
- 去除input填充颜色
- cuda event
- Is there anyway to discover which ip addresses are connected to the db?
- E-BERT: 电商领域语言模型优化实践
- Linux源码安装pgadmin4,linux安装pgadmin3
- 如何监控网页卡顿和崩溃?
- 10分钟搭建linux代理服务器
- Python3使用dbf模块读写dbf文件
- 无线测温系统在高低压开关柜内的运行---安科瑞 顾城
- JS打印表格时边框缺失问题
- 时空旅行的可能性(无聊研究社)
- 艺赛旗RPA8.0-用户体验提升抢先看(一)
- 说说如何在项目中引入 jBPM4 工作流框架以及遇到的坑儿
- 因子分析 二元logistic回归