(二十四)linux新定时器:timefd及相关操作函数
timerfd是Linux为用户程序提供的一个定时器接口。这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,所以能够被用于select/poll的应用场景。
一,相关操作函数
#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags);
int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
int timerfd_gettime(int fd, struct itimerspec *curr_value);
二,timerfd_create
int timerfd_create(int clockid, int flags);
它是用来创建一个定时器描述符timerfd
第一个参数:clockid指定时间类型,有两个值:
CLOCK_REALTIME :Systemwide realtime clock. 系统范围内的实时时钟
CLOCK_MONOTONIC:以固定的速率运行,从不进行调整和复位 ,它不受任何系统time-of-day时钟修改的影响
第二个参数:flags可以是0或者O_CLOEXEC/O_NONBLOCK。
返回值:timerfd(文件描述符)
三,timerfd_settime
在讲解该函数前,先理解两个相关结构体:
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 */
};
第二个结构体itimerspec就是timerfd要设置的超时结构体,它的成员it_value表示定时器第一次超时时间,it_interval表示之后的超时时间即每隔多长时间超时
int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
作用:用来启动或关闭有fd指定的定时器
参数:
fd:timerfd,有timerfd_create函数返回
fnew_value:指定新的超时时间,设定new_value.it_value非零则启动定时器,否则关闭定时器,如果new_value.it_interval为0,则定时器只定时一次,即初始那次,否则之后每隔设定时间超时一次
old_value:不为null,则返回定时器这次设置之前的超时时间
flags:1代表设置的是绝对时间;为0代表相对时间。
四,timerfd_gettime
int timerfd_gettime(int fd, struct itimerspec *curr_value);
此函数用于获得定时器距离下次超时还剩下的时间。如果调用时定时器已经到期,并且该定时器处于循环模式(设置超时时间时struct itimerspec::it_interval不为0),那么调用此函数之后定时器重新开始计时。
The it_value field returns the amount of time until the timer will next expire. If both fields of this structure are zero, then the timer is currently disarmed. This field always contains a relative value, regardless of whether the TFD_TIMER_ABSTIME flag was specified when setting the timer.
The it_interval field returns the interval of the timer. If both fields of this structure are zero, then the timer is set to expire just once, at the time specified by curr_value.it_value.
五,read读取timefd超时事件通知
read(2) If the timer has already expired one or more times since its settings were last modified using timerfd_settime(), or since the last successful read(2), then the buffer given to read(2) returns an unsigned 8-byte integer (uint64_t) containing the number of expirations that have occurred. (The returned value is in host byte order, i.e., the native byte order for integers on the host machine.)
If no timer expirations have occurred at the time of the read(2), then the call either blocks until the next timer expiration, or fails with the error EAGAIN if the file descriptor has been made nonblocking (via the use of the fcntl(2) F_SETFL operation to set theO_NONBLOCK flag).
A read(2) will fail with the error EINVAL if the size of the supplied buffer is less than 8 bytes.
当定时器超时,read读事件发生即可读,返回超时次数(从上次调用timerfd_settime()启动开始或上次read成功读取开始),它是一个8字节的unit64_t类型整数,如果定时器没有发生超时事件,则read将阻塞若timerfd为阻塞模式,否则返回EAGAIN 错误(O_NONBLOCK模式),如果read时提供的缓冲区小于8字节将以EINVAL错误返回。
六,示例代码
man手册中示例:
The following program creates a timer and then monitors its progress. The program accepts up to three command-line arguments. The first argument specifies the number of seconds for the initial expiration of the timer. The second argument specifies the interval for the timer, in seconds. The third argument specifies the number of times the program should allow the timer to expire before terminating. The second and third command-line arguments are optional.
#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 = ;
int secs, nsecs; if (first_call) {
first_call = ;
if (clock_gettime(CLOCK_MONOTONIC, &start) == -)
handle_error("clock_gettime");
} if (clock_gettime(CLOCK_MONOTONIC, &curr) == -)
handle_error("clock_gettime"); secs = curr.tv_sec - start.tv_sec;
nsecs = curr.tv_nsec - start.tv_nsec;
if (nsecs < ) {
secs--;
nsecs += ;
}
printf("%d.%03d: ", secs, (nsecs + ) / );
} 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 != ) && (argc != )) {
fprintf(stderr, "%s init-secs [interval-secs max-exp]\n",
argv[]);
exit(EXIT_FAILURE);
} if (clock_gettime(CLOCK_REALTIME, &now) == -)
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[]);
new_value.it_value.tv_nsec = now.tv_nsec;
if (argc == ) {
new_value.it_interval.tv_sec = ;
max_exp = ;
} else {
new_value.it_interval.tv_sec = atoi(argv[]);
max_exp = atoi(argv[]);
}
new_value.it_interval.tv_nsec = ; fd = timerfd_create(CLOCK_REALTIME, );
if (fd == -)
handle_error("timerfd_create"); if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -)
handle_error("timerfd_settime"); print_elapsed_time();
printf("timer started\n"); for (tot_exp = ; 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);
}
运行结果:

(二十四)linux新定时器:timefd及相关操作函数的更多相关文章
- linux新定时器:timefd及相关操作函数
timerfd是Linux为用户程序提供的一个定时器接口.这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,所以能够被用于select/poll的应用场景. 一,相关操作函数 #inclu ...
- 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用
目录 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用 24.1 expect实现无交互登录 24.1.1 安装和使用expect 24.2 正则表达式的使用 24 ...
- Linux学习之CentOS(二十六)--Linux磁盘管理:LVM逻辑卷的创建及使用
在上一篇随笔里面 Linux学习之CentOS(二十五)--Linux磁盘管理:LVM逻辑卷基本概念及LVM的工作原理,详细的讲解了Linux的动态磁盘管理LVM逻辑卷的基本概念以及LVM的工作原理, ...
- VMware vSphere 服务器虚拟化之二十四 桌面虚拟化之手动池管理物理机
VMware vSphere 服务器虚拟化之二十四 桌面虚拟化之手动池管理物理机 VMwareView手动池可以管理物理计算机 说明: 环境基于实验二十三 1.准备一台Windows 7的物理计算机名 ...
- (C/C++学习笔记) 二十四. 知识补充
二十四. 知识补充 ● 子类调用父类构造函数 ※ 为什么子类要调用父类的构造函数? 因为子类继承父类,会继承到父类中的数据,所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程. ...
- 条目二十四《当效率至关重要时,请在map::operator[]与map::insert之间谨慎做出选择》
条目二十四<当效率至关重要时,请在map::operator[]与map::insert之间谨慎做出选择> 当效率至关重要时,应该在map::operator[]和map::insert之 ...
- 使用Typescript重构axios(二十四)——防御XSRF攻击
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- Bootstrap<基础二十四> 缩略图
Bootstrap 缩略图.大多数站点都需要在网格中布局图像.视频.文本等.Bootstrap 通过缩略图为此提供了一种简便的方式.使用 Bootstrap 创建缩略图的步骤如下: 在图像周围添加带有 ...
- 二十四、Struts2中的UI标签
二十四.Struts2中的UI标签 Struts2中UI标签的优势: 数据回显 页面布局和排版(Freemark),struts2提供了一些常用的排版(主题:xhtml默认 simple ajax) ...
随机推荐
- 37-生成 JWT Token
接到上篇文章 安装扩展插件nuget package方法安装包 使用 ctrl+shift+p打开命令面板 增加这个包, Microsoft.AspNetCore.Authentication.Jw ...
- 笔记-scrapy-scarpyd
笔记-scrapy-scarpyd 1. scrapy部署 会写爬虫之后就是部署.管理爬虫了,下面讲一下如何部署scrapy爬虫. 现在使用较多的管理工具是Scrapyd. scrapyd是 ...
- Android Url相关工具 通用类UrlUtil
1.整体分析 1.1.源代码查看,可以直接Copy. public class UrlUtil { public static boolean isUrlPrefix(String url) { re ...
- 【转帖】LoadRunner系统架构简介
LoadRunner系统架构简介: LoadRunner是通过创建虚拟用户来代替真实实际用户来操作客户端软件比如Internet Explorer,来向IIS.Apache等Web服务器发送HTTP协 ...
- echart搭配时间轴进行展示 (本例展示的是多时间 多地区 多指标条件 )
1:照常先来几张图 看效果 2:首先 看官方文档 我把echart官方的例子给扒下来并整理了得出如下效果 上 案例图和代码 效果图 : 代码: <style type="text/c ...
- 我的转行之路(电气转IT)------2018阿里校招面经
博主本专业电气,今年3月下定决心转向互联网行业,本来想依仗自己比较自信的学习能力自学成才的,不过学了一段时间感觉还是需要一个人来指点,不仅仅是指点一些技术性的问题,更是需要有人来指点一下方向性的问题. ...
- linux socket下send()&recv()调用
1.send 函数 int send( SOCKET s, const char FAR *buf, int len, int flags ); 不论是客户还是服务器应用程序都用send函数来向TCP ...
- Erlang中常用的类型转换[转]
转自: http://blog.sina.com.cn/s/blog_53a5047b01018yqv.html 例子 结果 atom_to_list(hello). "hello" ...
- 使用闭包和lambda解决问题与常规方式解决问题的对比。
先来描述一下问题吧,游戏中的物品原来只有一个属性加成:攻击,防御,获得经验加成,金币加成,等等.现在要增加一个属性,这个属性可以为之前的属性之一. 这个属性加成涉及到类里的三个属性,value,typ ...
- 《Cracking the Coding Interview》——第3章:栈和队列——题目5
2014-03-18 05:33 题目:用两个栈来实现一个队列. 解法:栈是反的,队列是正的,反了再反就正过来了.所以,请看代码.操作中时间复杂度有O(1)的,有O(n)的,但均摊下来时间符合O(1) ...