美文网首页
timerfd总结

timerfd总结

作者: lwj_ow | 来源:发表于2019-09-26 20:34 被阅读0次

前言

又是隔了不短时间,不过每天也没怎么放松,一部分是自己在看libevent和udp通信的东西,暂时处于学习阶段,也谈不上什么写博客了,不过最近看到linux下新增的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 定时器间隔时间
    */
    
  4. read函数
    当定时器超时的时候,我们可以使用read函数来从之前通过timerfd_create函数创建的文件描述符中读取数据

    uint64_t exp = 0;
    read(fd, &exp, sizeof(uint64_t));
    //可以用read函数读取计时器的超时次数,改值是一个8字节无符号的长整型
    

使用例子

#include <errno.h>
#include <glog/logging.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <unistd.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);
  LOG(INFO) << 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();
  LOG(INFO) << "read: " << (unsigned long long)exp
            << ", total: " << (unsigned long long)tot_exp;
  // 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);
  LOG(INFO) << "epoll add fd:" << fd << "success";
  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);
  LOG(INFO) << "epoll fd:" << epfd << " create success";

  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) {
  google::InitGoogleLogging("INFO");
  FLAGS_logtostderr = true;
  if (epollfd_init() < 0) {
    return -1;
  }

  if (timerfd_init()) {
    return -1;
  }

  /* event handle */
  epoll_event_handle();

  return 0;
}

解释

这里我用了一下Google开源的日志库glog,利用这个来打印日志,这样会辅助显示时间,这样方便我们进行查看同时测试,这里我就简单贴下我的运行结果, image.png

,相对来说还是比较简单的,但是如果第一次接触的话估计有点陌生,这里我们简单总结一下,同时学习下其与epoll是如何配合完成超时通知的.

相关文章

  • timerfd总结

    前言 又是隔了不短时间,不过每天也没怎么放松,一部分是自己在看libevent和udp通信的东西,暂时处于学习阶段...

  • linux手册翻译——timerfd_create(2)

    timerfd_create, timerfd_settime, timerfd_gettime - timers...

  • timerfd

    Linux内核于内核2.6之后提供了一种创建定时器的方法,那就是Linux特有的timerfd文件描述符(一切皆文...

  • timerfd的使用方法

    timerfd的使用方法 文章来自:http://blog.csdn.net/yusiguyuan/article...

  • Linux timerfd系列函数

    使用Linux 提供的timerfd和epoll可以实现Timer的定时唤醒功能. 需要引入头文件#include...

  • Linux Timer定时器

    timerfd为Linux为用户程序提供的定时器接口,该接口基于文件描述符,通过文件描述符的可读事件进行超时通知,...

  • 专题总结(待续。。。)

    质粒总结 引物总结 抗体总结 细胞系总结 模式动物总结 机制功能总结

  • 工作总结――让你欢喜让你忧

    哇哈哈,工作总结...... 工作中,我们常会被要求写各种总结,活动总结、销售总结、培训总结、月总结、季度总结.....

  • 工作总结万能公式

    总结汇报是职场上经常遇到的事,有周总结、月总结、季度总结、年中总结、年终总结、重点项目总结、重要环节总结等...

  • 缺不了的总结

    从小到大,缺不了的总结。知识点总结,读书电影的观后感,章节总结,学科总结,学期总结,新年总结,工作周总结月总结年中...

网友评论

      本文标题:timerfd总结

      本文链接:https://www.haomeiwen.com/subject/fxjkjctx.html