您的位置:首页 > 运维架构 > Linux

epoll定时器实现系列文章:linux timerfd系列函数总结,有firecat注释

2018-02-13 16:01 531 查看
https://www.cnblogs.com/wenqiang/p/6698371.html
firecat注:引自muduo一书,8.2节。 https://github.com/chenshuo/muduo/blob/master/backport.diff
传统网络库的reactor通过控制select和poll,epoll的等待时间(epoll_wait函数的参数)来实现定时。而Linux内核在2.6版本后,新增了timerfd,可以更精确的定时。把这个fd当成普通网络IO事件相同的方式来处理定时。

网上关于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()函数
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.c
3 * Author: zhangwj
4 * Desprition: a sample program of timerfd
5 * Date: 2017-04-17
6 * 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 0
18 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 #endif
28
29 #define EPOLL_LISTEN_CNT        256
30 #define EPOLL_LISTEN_TIMEOUT    500
31
32 #define LOG_DEBUG_ON 1
33
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 #else
51 #define LOG_DEBUG(fmt, args...)
52 #define LOG_INFO(fmt, args...)
53 #define LOG_WARNING(fmt, args...)
54 #endif
55 #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 }

参考资料:http://www.man7.org/linux/man-pages/man2/timerfd_create.2.htmlhttp://blog.csdn.net/walkingman321/article/details/6162055
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: