timerfd是Linux为用户程序提供的一个定时器接口
2021/6/26 7:28:52
本文主要是介绍timerfd是Linux为用户程序提供的一个定时器接口,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
timerfd是Linux为用户程序提供的一个定时器接口。这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,因此可以配合select/poll/epoll等使用。
- 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将被系统自动关闭,表示不传递) */
- 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表示停止定时器 */
- 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 = 0; read(fd, &exp, sizeof(uint64_t)); //可以用read函数读取计时器的超时次数,改值是一个8字节无符号的长整型
timerfd配合epoll函数的简单例子
#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(0); #define LOG_INFO(fmt, args...) \ do { \ printf("[INFO]:");\ printf(fmt "\n", ##args); \ } while(0); #define LOG_WARNING(fmt, args...) \ do { \ printf("[WARNING]:");\ printf(fmt "\n", ##args); \ } while(0); #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(0); #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) static int g_epollfd = -1; static int g_timerfd = -1; uint64_t tot_exp = 0; static void help(void) { exit(0); } static void print_elapsed_time(void) { static struct timespec start; struct timespec curr; static int first_call = 1; int secs, nsecs; if (first_call) { first_call = 0; if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) handle_error("clock_gettime"); } if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1) handle_error("clock_gettime"); secs = curr.tv_sec - start.tv_sec; nsecs = curr.tv_nsec - start.tv_nsec; if (nsecs < 0) { secs--; nsecs += 1000000000; } printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000); } void timerfd_handler(int fd) { uint64_t exp = 0; 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 = 0; int fd_cnt = 0; int sfd; struct epoll_event events[EPOLL_LISTEN_CNT]; memset(events, 0, sizeof(events)); while(1) { /* wait epoll event */ fd_cnt = epoll_wait(g_epollfd, events, EPOLL_LISTEN_CNT, EPOLL_LISTEN_TIMEOUT); for(i = 0; 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, 0, sizeof(event)); event.data.fd = fd; event.events = EPOLLIN | EPOLLET; ret = epoll_ctl(g_epollfd, EPOLL_CTL_ADD, fd, &event); if(ret < 0) { LOG_ERROR("epoll_ctl Add fd:%d error, Error:[%d:%s]", fd, errno, strerror(errno)); return -1; } LOG_DEBUG("epoll add fd:%d--->%d success", fd, g_epollfd); return 0; } int epollfd_init() { int epfd; /* create epoll fd */ epfd = epoll_create(EPOLL_LISTEN_CNT); if (epfd < 0) { LOG_ERROR("epoll_create error, Error:[%d:%s]", errno, strerror(errno)); return -1; } 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 = 2; new_value.it_value.tv_nsec = 0; new_value.it_interval.tv_sec = 1; new_value.it_interval.tv_nsec = 0; tmfd = timerfd_create(CLOCK_MONOTONIC, 0); if (tmfd < 0) { LOG_ERROR("timerfd_create error, Error:[%d:%s]", errno, strerror(errno)); return -1; } ret = timerfd_settime(tmfd, 0, &new_value, NULL); if (ret < 0) { LOG_ERROR("timerfd_settime error, Error:[%d:%s]", errno, strerror(errno)); close(tmfd); return -1; } if (epoll_add_fd(tmfd)) { close(tmfd); return -1; } g_timerfd = tmfd; return 0; } int main(int argc, char **argv) { if (epollfd_init() < 0) { return -1; } if (timerfd_init()) { return -1; } /* event handle */ epoll_event_handle(); return 0; }
这篇关于timerfd是Linux为用户程序提供的一个定时器接口的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-18git仓库有更新,jenkins 自动触发拉代码怎么配置的?-icode9专业技术文章分享
- 2024-12-18Jenkins webhook 方式怎么配置指定的分支?-icode9专业技术文章分享
- 2024-12-13Linux C++项目实战入门教程
- 2024-12-13Linux C++编程项目实战入门教程
- 2024-12-11Linux部署Scrapy教程:新手入门指南
- 2024-12-11怎么将在本地创建的 Maven 仓库迁移到 Linux 服务器上?-icode9专业技术文章分享
- 2024-12-10Linux常用命令
- 2024-12-06谁看谁服! Linux 创始人对于进程和线程的理解是…
- 2024-12-04操作系统教程:新手入门及初级技巧详解
- 2024-12-04操作系统入门:新手必学指南