zoukankan      html  css  js  c++  java
  • 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()函数

     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 "
    ", ##args); 
     39     } while(0);
     40 #define LOG_INFO(fmt, args...) 
     41     do { 
     42         printf("[INFO]:");
     43         printf(fmt "
    ", ##args); 
     44     } while(0);
     45 #define LOG_WARNING(fmt, args...) 
     46     do { 
     47         printf("[WARNING]:");
     48         printf(fmt "
    ", ##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 "
    ", ##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
    ", (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.html

    http://blog.csdn.net/walkingman321/article/details/6162055

  • 相关阅读:
    oracle 导入数据时提示只有 DBA 才能导入由其他 DBA 导出的文件
    oracle 常用语句
    android udp 无法收到数据 (模拟器中)
    android DatagramSocket send 发送数据出错
    AtCoder ABC 128E Roadwork
    AtCoder ABC 128D equeue
    AtCoder ABC 127F Absolute Minima
    AtCoder ABC 127E Cell Distance
    CodeForces 1166E The LCMs Must be Large
    CodeForces 1166D Cute Sequences
  • 原文地址:https://www.cnblogs.com/wenqiang/p/6698371.html
Copyright © 2011-2022 走看看