linux timerfd系列函数总结
网上关于timerfd的文章很多,在这儿归纳总结一下方便以后使用,顺便贴出一个timerfd配合epoll使用的简单例子
一、timerfd系列函数
timerfd是Linux为用户程序提供的一个定时器接口。这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,因此可以配合select/poll/epoll等使用。
下面对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()函数
#include <sys/timerfd.h> 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 (第一次超时时间)*/
};
int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
/*
timerfd_settime()此函数用于设置新的超时时间,并开始计时,能够启动和停止定时器;
fd: 参数fd是timerfd_create函数返回的文件句柄
flags:参数flags为1代表设置的是绝对时间(TFD_TIMER_ABSTIME 表示绝对定时器);为0代表相对时间。
new_value: 参数new_value指定定时器的超时时间以及超时间隔时间
old_value: 如果old_value不为NULL, old_vlaue返回之前定时器设置的超时时间,具体参考timerfd_gettime()函数 ** it_interval不为0则表示是周期性定时器。
it_value和it_interval都为0表示停止定时器
*/
(3)timerfd_gettime()函数
int timerfd_gettime(int fd, struct itimerspec *curr_value);
/*
timerfd_gettime()函数获取距离下次超时剩余的时间
curr_value.it_value 字段表示距离下次超时的时间,如果改值为0,表示计时器已经解除
改字段表示的值永远是一个相对值,无论TFD_TIMER_ABSTIME是否被设置
curr_value.it_interval 定时器间隔时间
*/
uint64_t exp = ;
read(fd, &exp, sizeof(uint64_t));
//可以用read函数读取计时器的超时次数,改值是一个8字节无符号的长整型
(4)下面贴出一个timerfd配合epoll函数的简单例子
/********************************************************
* Filename: timerfd.c
* Author: zhangwj
* Desprition: a sample program of timerfd
* Date: 2017-04-17
* Warnning:
********************************************************/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <sys/epoll.h>
#include <sys/timerfd.h> #if 0
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 */
};
#endif #define EPOLL_LISTEN_CNT 256
#define EPOLL_LISTEN_TIMEOUT 500 #define LOG_DEBUG_ON 1 #ifdef LOG_DEBUG_ON
#define LOG_DEBUG(fmt, args...) \
do { \
printf("[DEBUG]:");\
printf(fmt "\n", ##args); \
} while();
#define LOG_INFO(fmt, args...) \
do { \
printf("[INFO]:");\
printf(fmt "\n", ##args); \
} while();
#define LOG_WARNING(fmt, args...) \
do { \
printf("[WARNING]:");\
printf(fmt "\n", ##args); \
} while();
#else
#define LOG_DEBUG(fmt, args...)
#define LOG_INFO(fmt, args...)
#define LOG_WARNING(fmt, args...)
#endif
#define LOG_ERROR(fmt, args...) \
do{ \
printf("[ERROR]:");\
printf(fmt "\n", ##args);\
}while(); #define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while () static int g_epollfd = -;
static int g_timerfd = -;
uint64_t tot_exp = ; static void help(void)
{
exit();
} 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 + ) / );
} void timerfd_handler(int fd)
{
uint64_t exp = ; read(fd, &exp, sizeof(uint64_t));
tot_exp += exp;
print_elapsed_time();
printf("read: %llu, total: %llu\n", (unsigned long long)exp, (unsigned long long)tot_exp); return;
} void epoll_event_handle(void)
{
int i = ;
int fd_cnt = ;
int sfd;
struct epoll_event events[EPOLL_LISTEN_CNT]; memset(events, , sizeof(events));
while()
{
/* wait epoll event */
fd_cnt = epoll_wait(g_epollfd, events, EPOLL_LISTEN_CNT, EPOLL_LISTEN_TIMEOUT);
for(i = ; i < fd_cnt; i++)
{
sfd = events[i].data.fd;
if(events[i].events & EPOLLIN)
{
if (sfd == g_timerfd)
{
timerfd_handler(sfd);
}
}
}
}
} int epoll_add_fd(int fd)
{
int ret;
struct epoll_event event; memset(&event, , sizeof(event));
event.data.fd = fd;
event.events = EPOLLIN | EPOLLET; ret = epoll_ctl(g_epollfd, EPOLL_CTL_ADD, fd, &event);
if(ret < ) {
LOG_ERROR("epoll_ctl Add fd:%d error, Error:[%d:%s]", fd, errno, strerror(errno));
return -;
} LOG_DEBUG("epoll add fd:%d--->%d success", fd, g_epollfd);
return ;
} int epollfd_init()
{
int epfd; /* create epoll fd */
epfd = epoll_create(EPOLL_LISTEN_CNT);
if (epfd < ) {
LOG_ERROR("epoll_create error, Error:[%d:%s]", errno, strerror(errno));
return -;
}
g_epollfd = epfd;
LOG_DEBUG("epoll fd:%d create success", epfd); return epfd;
} int timerfd_init()
{
int tmfd;
int ret;
struct itimerspec new_value; new_value.it_value.tv_sec = ;
new_value.it_value.tv_nsec = ;
new_value.it_interval.tv_sec = ;
new_value.it_interval.tv_nsec = ; tmfd = timerfd_create(CLOCK_MONOTONIC, );
if (tmfd < ) {
LOG_ERROR("timerfd_create error, Error:[%d:%s]", errno, strerror(errno));
return -;
} ret = timerfd_settime(tmfd, , &new_value, NULL);
if (ret < ) {
LOG_ERROR("timerfd_settime error, Error:[%d:%s]", errno, strerror(errno));
close(tmfd);
return -;
} if (epoll_add_fd(tmfd)) {
close(tmfd);
return -;
}
g_timerfd = tmfd; return ;
} int main(int argc, char **argv)
{
if (epollfd_init() < ) {
return -;
} if (timerfd_init()) {
return -;
} /* event handle */
epoll_event_handle(); return ;
}
参考资料:
http://www.man7.org/linux/man-pages/man2/timerfd_create.2.html
http://blog.csdn.net/walkingman321/article/details/6162055
linux timerfd系列函数总结的更多相关文章
- Linux中exec()执行文件系列函数的使用说明
函数原型: 描述: exec()系列函数使用新的进程映像替换当前进程映像. 工作方式没有什么差别, 只是参数传递的方式不同罢了. 说明: 1. 这6个函数可分为两大类: execl( ...
- Linux Shell系列教程之(十五) Shell函数简介
本文是Linux Shell系列教程的第(十五)篇,更多Linux Shell教程请看:Linux Shell系列教程 函数可以将一个复杂功能划分成若干模块,从而使程序结构更加清晰,代码重复利用率更高 ...
- linux tricks 之VA系列函数.
VA函数(variable argument function),参数个数可变函数,又称可变参数函数.C/C++编程中,系统提供给编程人员的va函数很少.*printf()/*scanf()系列函数, ...
- linux系统编程之进程(五):exec系列函数(execl,execlp,execle,execv,execvp)使用
本节目标: exec替换进程映像 exec关联函数组(execl.execlp.execle.execv.execvp) 一,exec替换进程映像 在进程的创建上Unix采用了一个独特的方法,它将进程 ...
- posix 线程(一):线程模型、pthread 系列函数 和 简单多线程服务器端程序
posix 线程(一):线程模型.pthread 系列函数 和 简单多线程服务器端程序 一.线程有3种模型,分别是N:1用户线程模型,1:1核心线程模型和N:M混合线程模型,posix thread属 ...
- c/c++ linux epoll系列3 利用epoll_wait设置timeout时间长度
linux epoll系列3 利用epoll_wait设置timeout时间长度 epoll_wait函数的第四个参数可以设置,epoll_wait函数的等待时间(timeout时间长度). 例子1, ...
- c/c++ linux epoll系列2 利用epoll_wait查看是否可以送信
linux epoll系列2 利用epoll_wait查看是否可以送信 write函数本来是非阻塞函数,但是当缓存区被写满后,再往缓存区里写的时候,就必须等待缓存区再次变成可写,所以这是write就变 ...
- c/c++ linux epoll系列1 创建epoll
linux epoll系列1 创建epoll 据说select和poll的弱点是,随着连接(socket)的增加,性能会直线下降. epoll不会随着连接(socket)的增加,性能直线下降. 知识点 ...
- c/c++ linux 进程间通信系列5,使用信号量
linux 进程间通信系列5,使用信号量 信号量的工作原理: 由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的: P(sv):如果sv的值大于零,就给它减1:如果 ...
随机推荐
- Android Bootloader LittleKernel的两篇文章
Android 开发之 ---- bootloader (LK) LK是什么 LK 是 Little Kernel 它是 appsbl (Applications ARM Boot Loader)流程 ...
- Android进阶(十八)AndroidAPP开发问题汇总(二)
Android进阶(十八)AndroidAPP开发问题汇总(二) 端口被占用解决措施: Android使用SimpleAdapter更新ListView里面的Drawable元素: http://ww ...
- 介绍一种很棒的wince 如何替换系统声音的方法
Topic:介绍一种很棒的wince 如何替换系统声音的方法(作者:Baiduluckyboy) //------------------------------------------------- ...
- ROS探索总结(十四)——move_base(路径规划)
在上一篇的博客中,我们一起学习了ROS定位于导航的总体框架,这一篇我们主要研究其中最重要的move_base包. 在总体框架图中可以看到,move_base提供了ROS导航的配置.运行.交互接口,它主 ...
- 部署与管理ZooKeepe
1.部署 本章节主要讲述如何部署ZooKeeper,包括以下三部分的内容: 1. 系统环境 2. 集群模式的配置 3. 单机模式的配置 系统环境和集群模式配置这两节内容大体讲述了如何部署一个能够用于生 ...
- UITabbar的一些常规用法(总结)
往往系统自带的UITabbar 不能满足我们的样式或者颜色设计,所以需要调整UITabbar. 1.自定义UITabbar,也是我学到的第一种方式(简单暴力). 先记录一下思路: 首先,隐藏系统自带的 ...
- 关于linux内核驱动开发中Makefile编译的问题
obj-y:打个比方,我要编译的是hello.c这个文件,obj-y就会把hello.c或者hello.c编译生成的hello.s文件链接到内核中去. obj-m:打个比方,我要编译的是hello.c ...
- 如何用Dreamweaver编辑rails的html.erb文件
默认情况下用dw是以普通的text文件打开html.erb文件,这多少让人有点不爽.其实dw打开erb文件也是相当的容易,下面就简单说下在mac os X下如何让dw支持erb文件: 首先找到dw的用 ...
- ip地址扫描
自己写的一个ip地址扫描脚本,功能是输入ip地址和掩码,通过ping检测整个网段的ip地址,输出ping的结果. 主要的几个函数如下: 1.ip地址转化为数值,方便计算 ip2num() { ip=$ ...
- ethtool确定网卡对应的物理网口
在配置有多个网络接口的设备时我们会犯难,eth0.eth1.--到底是那个接口? 我使用的机器是CentOS系统,打开终端,输入ethtool –help 显示帮助信息,下面我就简要介绍一下最常用的两 ...