timerfd API使用总结

timerfd 介绍

timerfd 是在Linux内核2.6.25版本中添加的接口,其是Linux为用户提供的一个定时器接口。这个接口基于文件描述符,所以可以被用于select/poll/epoll的场景。当使用timerfd API创建多个定时器任务并置于poll中进行事件监听,当没有可响应的事件,则程序阻塞在poll中,当有事件发生,通过poll的这个事件入口,对产生的事件进行响应,从而构成了一个事件轮训程序。

timerfd 相关函数

#include <time.h>
int clock_gettime(clockid_t clockid, struct timespec *tp);
  • 1
  • 2
  • 3

clock_gettime函数主要用于获取系统时间,精确到纳秒级别。在编译时需要添加-lrt库,clockid_t clockid指定用何种模式获取时间,struct timespec *tp用于存储获取到的时间。其中clockid主要有如下常用的参数: 
CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,中间时刻如果系统时间被用户改成其他,则对应的时间相应改变 
CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响 
  CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统CPU花费的时间 
  CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统CPU花费的时间

#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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • timerfd_create函数主要用于生成一个定时器对象,返回与之关联的文件描述符,clockid可以设置CLOCK_REALTIME和CLOCK_MONOTONIC,flags可以设置为TFD_NONBLOCK(非阻塞),TFD_CLOEXEC(同O_CLOEXEC)
  • timerfd_settime用于启动和停止定时器,fd为timerfd_create获得的定时器文件描述符,flags为0表示是相对定时器,为TFD_TIMER_ABSTIME表示是绝对定时器。const struct itimerspec *new_value表示设置超时的时间。 
    其数据结构:
  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 */};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

需要注意的是itimerspec 结构成员表示的意义: 
it_value是首次超时时间,需要填写从clock_gettime获取的时间,并加上要超时的时间。 it_interval是后续周期性超时时间,是多少时间就填写多少。 
it_interval不为0则表示是周期性定时器。 
it_value和it_interval都为0表示停止定时器。

  • timerfd_gettime此函数用于获得定时器距离下次超时还剩下的时间。如果调用时定时器已经到期,并且该定时器处于循环模式(设置超时时间时struct itimerspec::it_interval不为0),那么调用此函数之后定时器重新开始计时。

参考示例

示例一


int tu_set_timer(tu_timer_t * timer, uint64_t milliseconds, bool continious, timer_handler_cb_t timer_handler_cb, void * timer_handler_arg)
{int fd;struct itimerspec its;//创建的定时器    fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);if (fd == -1){LOG_PRINT("Error creating timer");return -1;}//设置超时时间its.it_value.tv_sec = (milliseconds * 1000000) / 1000000000;its.it_value.tv_nsec = (milliseconds * 1000000) % 1000000000;//如果是周期定时器,则设置it_interval,如果不是则为0its.it_interval.tv_sec = continious ? its.it_value.tv_sec : 0;its.it_interval.tv_nsec = continious ? its.it_value.tv_nsec : 0;//设置定时到达后的响应函数及其函数参数timer->timer_handler_cb = timer_handler_cb;timer->timer_handler_arg = timer_handler_arg;timer->continious = continious;//标记是否为循环周期定时器//启动定时器,并将文件描述符添加到poll中监听if ((timerfd_settime(fd, 0, &its, NULL) == 0) && ((timer->fd_index = polling_define_poll_fd(fd, POLLIN, tu_timer_handler, timer)) != -1)){timer->in_use = true;return 0;}close(fd);return -1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

示例二


int tu_set_timer_realtime(tu_timer_t * timer, uint64_t milliseconds, bool continious, timer_handler_cb_t timer_handler_cb, void * timer_handler_arg)
{int fd;struct itimerspec its;struct timespec now;time_t tv_sec;long tv_nsec;//获取绝对时间if(clock_gettime(CLOCK_REALTIME,&now) == -1){LOG_PRINT("Error clock_gettime timer\n");return -1;}//创建定时器,非阻塞方式   fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK);if (fd == -1){LOG_PRINT("Error creating timer\n");return -1;}//计算时间tv_sec = (milliseconds * 1000000) / 1000000000;tv_nsec = (milliseconds * 1000000) % 1000000000;//设置到期时间its.it_value.tv_sec  = now.tv_sec + tv_sec;its.it_value.tv_nsec = now.tv_nsec + tv_nsec;//如果使用循环模式,设置循环间隔its.it_interval.tv_sec = continious ? tv_sec : 0;its.it_interval.tv_nsec = continious ? tv_nsec : 0;//设置定时到达后的响应函数及其函数参数timer->timer_handler_cb = timer_handler_cb;timer->timer_handler_arg = timer_handler_arg;timer->continious = continious;//启动定时器,并将文件描述符添加到poll中监听if ((timerfd_settime(fd,TFD_TIMER_ABSTIME, &its, NULL) == 0) && ((timer->fd_index = polling_define_poll_fd(fd, POLLIN, tu_timer_handler, timer)) != -1)){timer->in_use = true;LOG_PRINT("tu_set_timer_realtime--\n");return 0;}LOG_PRINT("Error setting timer\n");close(fd);return -1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

poll中的回调函数

void tu_timer_handler(void * arg)
{tu_timer_t * timer = arg;uint64_t exp;if (timer->continious)//重复定时器{if (read(polling_fds[timer->fd_index].fd, &exp, sizeof(uint64_t)) != sizeof(uint64_t)){LOG_PRINT("%p ERROR timer read. Killing timer.\n", timer);tu_kill_timer(timer);}}else{tu_kill_timer(timer);//关闭定时器}//调用定时器处理函数timer->timer_handler_cb(timer->timer_handler_arg);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384995.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

#if/#else/#endif

在linux环境下写c代码时会尝试各种方法或调整路径&#xff0c;需要用到#if #include<stdio.h>int main(){int i; #if 0i 1; #elsei 2; #endifprintf("i %d",i);return 0; } 有时候会调整代码&#xff0c;但是又不是最终版本的更换某些值&#xff0c;就需要注…

内存分配调用

通过函数给实参分配内存&#xff0c;可以通过二级指针实现 #include<stdio.h> #incldue<stdlib.h>void getheap(int *p) //错误的模型 {p malloc(100); }void getheap(int **p) //正确的模型 {*p malloc(100); } int main() {int *p NULL;getheap(&p);free(p…

ESP传输模式拆解包流程

一、 ESP简介ESP&#xff0c;封装安全载荷协议(Encapsulating SecurityPayloads)&#xff0c;是一种Ipsec协议&#xff0c;用于对IP协议在传输过程中进行数据完整性度量、来源认证、加密以及防回放攻击。可以单独使用&#xff0c;也可以和AH一起使用。在ESP头部之前的IPV4…

结构体成员内存对齐

#include<stdio.h> struct A {int A; };int main() {struct A a;printf("%d\n",sizeof(a));return 0; } 运行结果&#xff1a;4 #include<stdio.h> struct A {int a;int b&#xff1b; };int main() {struct A a;printf("%d\n",sizeof(a))…

C库函数-fgets()

函数声明&#xff1a;char *fgets(char *str,int n,FILE *stream) 函数介绍&#xff1a;从指定的stream流中读取一行&#xff0c;并把它存储在str所指向的字符串中。当读取到&#xff08;n-1&#xff09;个字符时&#xff0c;获取读取到换行符时&#xff0c;或者到达文件末尾时…

linux内核netfilter模块分析之:HOOKs点的注册及调用

1: 为什么要写这个东西?最近在找工作,之前netfilter 这一块的代码也认真地研究过&#xff0c;应该每个人都是这样的你懂 不一定你能很准确的表达出来。 故一定要化些时间把这相关的东西总结一下。 0&#xff1a;相关文档linux 下 nf_conntrack_tuple 跟踪记录 其中可以根据内…

指定结构体元素的位字段

struct B {char a:4; //a这个成员值占了4bitchar b:2;char c:2; } 占了1个字节 struct B {int a:4; //a这个成员值占了4bitchar b:2;char c:2; } 占了8个字节 控制LED灯的结构体&#xff1a; struct E {char a1:1;char a2:1;char a3:1;char a4:1;char a5:1;char a6:1;char a7:1…

网络抓包工具 wireshark 入门教程

Wireshark&#xff08;前称Ethereal&#xff09;是一个网络数据包分析软件。网络数据包分析软件的功能是截取网络数据包&#xff0c;并尽可能显示出最为详细的网络数据包数据。Wireshark使用WinPCAP作为接口&#xff0c;直接与网卡进行数据报文交换。网络管理员使用Wireshark来…

结构体中指针

结构体中带有指针的情况 #include<stdio.h>struct man {char *name;int age; };int main() {struct man m {"tom",20};printf("name %s, age %d\n",m.name,m.age);return 0; } 运行结果&#xff1a; exbotubuntu:~/wangqinghe/C/20190714$ gcc st…

python使用opencv提取视频中的每一帧、最后一帧,并存储成图片

提取视频每一帧存储图片 最近在搞视频检测问题&#xff0c;在用到将视频分帧保存为图片时&#xff0c;图片可以保存&#xff0c;但是会出现(-215:Assertion failed) !_img.empty() in function cv::imwrite问题而不能正常运行&#xff0c;在检查代码、检查路径等措施均无果后&…

结构体参数

结构体作为函数参数&#xff1a; #include<stdio.h> #include<stdlib.h> #include<string.h>struct student {char name[10];int age; };void print_student(struct student s) {printf("name %s,age %d\n",s.name,s.age); } void set_studen…

线程间通信之eventfd

线程间通信之eventfd man手册中的解释&#xff1a; eventfd()创建了一个“eventfd对象”&#xff0c; 通过它能够实现用户态程序间(我觉得这里主要指线程而非进程)的等待/通知机制&#xff0c;以及内核态向用户态通知的机制&#xff08;未考证&#xff09;。 此对象包含了一个…

【linux 开发】定时器使用setitimer

setitimer Linux 为每一个进程提供了 3 个 setitimer 间隔计时器&#xff1a; ITIMER_REAL&#xff1a;减少实际时间&#xff0c;到期的时候发出 SIGALRM 信号。ITIMER_VIRTUAL&#xff1a;减少有效时间 (进程执行的时间)&#xff0c;产生 SIGVTALRM 信号。ITIMER_PROF&#…

文件操作(写)

/*** file.c ***/ #include<stdio.h>int main() {//用写的方式打开一个文件 //w的意思是文件如果不存在&#xff0c;就建立一个文件&#xff0c;如果文件存在就覆盖FILE *p fopen("/home/exbot/wangqinghe/C/20190716/file1.txt","w");fputs(&qu…

定时器timerfd

1.为什么要加入此定时器接口 linux2.6.25版本新增了timerfd这个供用户程序使用的定时接口&#xff0c;这个接口基于文件描述符&#xff0c;当超时事件发生时&#xff0c;该文件描述符就变为可读。我首次接触这个新特性是在muduo网络库的定时器里看到的&#xff0c;那么新增一个…

文件操作(读)

读一行&#xff1a; #include<stdio.h> #include<string.h> #include<stdlib.h> const int maxn 10; int main() {char s[1024] {0};FILE *p fopen("/home/exbot/wangqinghe/C/20190716/file.txt","r");//第一个参数是一个内存地址&…

timerfd与epoll

linux timerfd系列函数总结 网上关于timerfd的文章很多&#xff0c;在这儿归纳总结一下方便以后使用&#xff0c;顺便贴出一个timerfd配合epoll使用的简单例子 一、timerfd系列函数 timerfd是Linux为用户程序提供的一个定时器接口。这个接口基于文件描述符&#xff0c;通过文…

文件操作(解密加密)

文件加密&#xff1a; #include<stdio.h> #include<string.h> #include<stdlib.h>void code(char *s) {while(*s){(*s);s;} }int main() {char s[1024] {0};FILE *p fopen("/home/exbot/wangqinghe/C/20190716/file.txt","r");FILE *p…

linux僵尸进程产生的原因以及如何避免产生僵尸进程defunct

给进程设置僵尸状态的目的是维护子进程的信息&#xff0c;以便父进程在以后某个时间获取。这些信息包括子进程的进程ID、终止状态以及资源利用信息(CPU时间&#xff0c;内存使用量等等)。如果一个进程终止&#xff0c;而该进程有子进程处于僵尸状态&#xff0c;那么它的所有僵尸…

linux下僵尸进程(Defunct进程)的产生与避免

在测试基于 DirectFBGstreamer 的视频联播系统的一个 Demo 的时候&#xff0c;其中大量使用 system 调用的语句&#xff0c;例如在 menu 代码中的 system("./play") &#xff0c;而且多次执行&#xff0c;这种情况下&#xff0c;在 ps -ef 列表中出现了大量的 defunc…