在libevent中定时器的实现是通过基于最小堆的优先级队列来实现的,对于这两个数据结构比较陌生的可以去翻算法导论的6.5节中,主要的源码都在min_heap.c中,下面是C++的实现。

数据结构

typedef struct min_heap
{struct event** p;unsigned n, a;
} min_heap_t;

在这个数据结构中 p也就是整个优先级队列,而这个优先级队列的每个节点都是一个struct *event.n表示这个队列的元素个数。a表示这个队列的大小。

#ifndef VOS_TIMER_H_
#define VOS_TIMER_H_  #define RELATIVE_TIMER 1
#define ABSOLUTE_TIMER 2  namespace vos
{  struct event;
typedef struct min_heap
{  struct event** p;  unsigned n, a;
} min_heap_t;  class Timer
{
public:  Timer();  virtual ~Timer();  /************************************** * input: interval: 每次执行的时间隔间, 单位是毫秒。 *        fun arg : 回调函数以及参数。 *        flag    : 绝对定时器还是相对定时器,如果是相对定时器 *        exe_num : 只有在相对定时器才有效,表示执行的次数。最少为1次 * return: 生成定时器的ID **************************************/  unsigned int timer_add(int interval, void (*fun)(void*), void *arg,  int flag = ABSOLUTE_TIMER,  int exe_num = 0);  /*************************************** * description: * 去掉已经加入的定时器,比如产生定时器的母体已经消亡了,在消亡之间要将其删除。 * 相对定时器在任务完成后会Timer会自己释放掉。 ***************************************/  bool timer_remove(unsigned int timer_id);  /*************************************** * description: Timer属于被动对象,没有自己的执行线程,属于被调用者。这样主要是为了避免产生线程同步。 * 定时器的循环处理函数,由定时器的拥有者进行循环调用。它的最小时间间隔决定了定时器的精度。 ***************************************/  int timer_process();  private:  struct min_heap _min_heap;  unsigned int _timer_id;
};  } /* namespace vos */
#endif /* VOS_TIMER_H_ */
#include "vos_timer.h"  #ifndef __WINDOWS
#include <sys/time.h>
#else
#include <windows.h>
#endif  #include <time.h>
#include <stdio.h>
#include <stdlib.h>  #define evutil_timercmp(tvp, uvp, cmp)                          \  (((tvp)->tv_sec == (uvp)->tv_sec) ?                           \  ((tvp)->tv_usec cmp (uvp)->tv_usec) :                     \  ((tvp)->tv_sec cmp (uvp)->tv_sec))  #define evutil_timersub(tvp, uvp, vvp)                      \  do {                                                    \  (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;     \  (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;  \  if ((vvp)->tv_usec < 0) {                         \  (vvp)->tv_sec--;                             \  (vvp)->tv_usec += 1000000;                       \  }                                                   \  } while (0)  #define evutil_timeradd(tvp, uvp, vvp)                          \  do {                                                        \  (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;         \  (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \  if ((vvp)->tv_usec >= 1000000) {                      \  (vvp)->tv_sec++;                                 \  (vvp)->tv_usec -= 1000000;                           \  }                                                       \  } while (0)  #ifdef __WINDOWS
int gettimeofday(struct timeval* tv, void * attr)
{  union  {  long long ns100;  FILETIME ft;  }now;  GetSystemTimeAsFileTime (&now.ft);  tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL);  tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL);  return (0);
}
#endif  namespace vos
{
struct event
{  unsigned int min_heap_idx; /* for managing timeouts */  unsigned int timer_id;  struct timeval ev_interval;  struct timeval ev_timeout;  int ev_exe_num;  void (*ev_callback)(void *arg);  void *ev_arg;  int ev_res; /* result passed to event callback */  int ev_flags;
};  /***构造函数  ***************/
static inline void min_heap_ctor(min_heap_t* s);
/***析构函数  ***************/
static inline void min_heap_dtor(min_heap_t* s);
/***初始化函数  ***************/
static inline void min_heap_elem_init(struct event* e);
/****比较函数***************/
static inline int min_heap_elem_greater(struct event *a, struct event *b);  static inline int min_heap_empty(min_heap_t* s);  static inline unsigned min_heap_size(min_heap_t* s);
/****返回栈顶元素************/
static inline struct event* min_heap_top(min_heap_t* s);
/****调整定时器的大小*********/
static inline int min_heap_reserve(min_heap_t* s, unsigned n);
/****放入数据*************/
static inline int min_heap_push(min_heap_t* s, struct event* e);
/****取得最后上面的数据******/
static inline struct event* min_heap_pop(min_heap_t* s);
/****消除一个定时器元素*******/
static inline int min_heap_erase(min_heap_t* s, struct event* e);
/****向上调整 ************/
static inline void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e);
/****向下调整************/
static inline void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e);  static inline void gettime(struct timeval *tm);  Timer::Timer() :  _timer_id(0)
{  min_heap_ctor(&_min_heap);
}  Timer::~Timer()
{  for (int i = 0; i < _min_heap.n; i++)  {  free(_min_heap.p[i]);  }  min_heap_dtor(&_min_heap);
}  unsigned int Timer::timer_add(int interval, void(*fun)(void*), void *arg,  int flag /* = ABSOLUTE_TIMER */, int exe_num /* =  0 */)
{  struct event * ev = (struct event*) malloc(sizeof(struct event));  min_heap_elem_init(ev);  if (NULL == ev)  return NULL;  struct timeval now;  gettime(&now);  ev->ev_interval.tv_sec = interval / 1000;  ev->ev_interval.tv_usec = (interval % 1000) * 1000;  evutil_timeradd(&now, &(ev->ev_interval), &(ev->ev_timeout));  ev->ev_flags = flag;  ev->ev_callback = fun;  ev->ev_arg = arg;  ev->ev_exe_num = exe_num;  ev->timer_id = _timer_id++;  min_heap_push(&_min_heap, ev);  return ev->timer_id;
}  bool Timer::timer_remove(unsigned int timer_id)
{  for (int i = 0; i < _min_heap.n; i++)  {  if (timer_id == _min_heap.p[i]->timer_id)  {  struct event * e = _min_heap.p[i];  min_heap_erase(&_min_heap, _min_heap.p[i]);  free(e);  return true;  }  }  return false;
}  int Timer::timer_process()
{  struct event *event;  struct timeval now;  while ((event = min_heap_top(&_min_heap)) != NULL)  {  gettime(&now);  if (evutil_timercmp(&now, &(event->ev_timeout), < ))  break;  min_heap_pop(&_min_heap);  event->ev_callback(event->ev_arg);  if (event->ev_flags == ABSOLUTE_TIMER  || (event->ev_flags == RELATIVE_TIMER && --event->ev_exe_num > 0))  {  evutil_timeradd(&(event->ev_timeout), &(event->ev_interval), &(event->ev_timeout));  min_heap_push(&_min_heap, event);  }  else  {  free(event);  }  }  return 0;
}  void gettime(struct timeval *tm)
{  gettimeofday(tm, NULL);
}  int min_heap_elem_greater(struct event *a, struct event *b)
{  return evutil_timercmp(&a->ev_timeout, &b->ev_timeout, >);
}  void min_heap_ctor(min_heap_t* s)
{  s->p = 0;  s->n = 0;  s->a = 0;
}  void min_heap_dtor(min_heap_t* s)
{  if (s->p)  free(s->p);
}  void min_heap_elem_init(struct event* e)
{  e->min_heap_idx = -1;
}  int min_heap_empty(min_heap_t* s)
{  return 0u == s->n;
}  unsigned min_heap_size(min_heap_t* s)
{  return s->n;
}  struct event* min_heap_top(min_heap_t* s)
{  return s->n ? *s->p : 0;
}  int min_heap_push(min_heap_t* s, struct event* e)
{  if (min_heap_reserve(s, s->n + 1))  return -1;  min_heap_shift_up_(s, s->n++, e);  return 0;
}  struct event* min_heap_pop(min_heap_t* s)
{  if (s->n)  {  struct event* e = *s->p;  min_heap_shift_down_(s, 0u, s->p[--s->n]);  e->min_heap_idx = -1;  return e;  }  return 0;
}  int min_heap_erase(min_heap_t* s, struct event* e)
{  if (((unsigned int) -1) != e->min_heap_idx)  {  struct event *last = s->p[--s->n];  unsigned parent = (e->min_heap_idx - 1) / 2;  /* we replace e with the last element in the heap.  We might need to shift it upward if it is less than its parent, or downward if it is greater than one or both its children. Since the children are known to be less than the parent, it can't need to shift both up and down. */  if (e->min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))  min_heap_shift_up_(s, e->min_heap_idx, last);  else  min_heap_shift_down_(s, e->min_heap_idx, last);  e->min_heap_idx = -1;  return 0;  }  return -1;
}  int min_heap_reserve(min_heap_t* s, unsigned n)
{  if (s->a < n)  {  struct event** p;  unsigned a = s->a ? s->a * 2 : 8;  if (a < n)  a = n;  if (!(p = (struct event**) realloc(s->p, a * sizeof *p)))  return -1;  s->p = p;  s->a = a;  }  return 0;
}  void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
{  unsigned parent = (hole_index - 1) / 2;  while (hole_index && min_heap_elem_greater(s->p[parent], e))  {  (s->p[hole_index] = s->p[parent])->min_heap_idx = hole_index;  hole_index = parent;  parent = (hole_index - 1) / 2;  }  (s->p[hole_index] = e)->min_heap_idx = hole_index;
}  void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
{  unsigned min_child = 2 * (hole_index + 1);  while (min_child <= s->n)  {  min_child -= min_child == s->n  || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);  if (!(min_heap_elem_greater(e, s->p[min_child])))  break;  (s->p[hole_index] = s->p[min_child])->min_heap_idx = hole_index;  hole_index = min_child;  min_child = 2 * (hole_index + 1);  }  min_heap_shift_up_(s, hole_index, e);
}
} /* namespace vos */  

基于Libevent最小根堆定时器的C++定时器实现相关推荐

  1. 基于小根堆实现的定时器

    基于小根堆实现的定时器 最小堆 定义 插入节点 删除节点 最小堆的实现 vector+unordered_map 具体功能 std::function< void() > 和 std::b ...

  2. 基于Libevent的HTTP Server

    简单的Http Server 使用Libevent内置的http相关接口,可以很容易的构建一个Http Server,一个简单的Http Server如下: #include <event2/e ...

  3. 前K个高频元素[小根堆和大根堆的使用]

    小根堆 前言 一.前K个高频元素 二.小根堆&大根堆 1.O(KlogN)大根堆 2.O(NlogK)小根堆 总结 参考文献 前言 当题目需要有序性时,果断排序,可二分快速寻找答案,或是利用有 ...

  4. 堆——神奇的优先队列 大根堆小根堆详解,附小根堆C++代码实现与STL相关

    文章目录 前置知识 堆操作 小根堆插入 代码实现 小根堆删除 代码实现 测试代码 STL实现--priority_queue 1.使用 2.创建 3.成员函数 前置知识 堆是一个完全二叉树(最后一层可 ...

  5. 堆(大根堆、小根堆)

    完全二叉堆 堆又可称之为完全二叉堆.这是一个逻辑上基于完全二叉树.物理上一般基于线性数据结构(如数组.向量.链表等)的一种数据结构. 完全二叉树的存储结构 学习过完全二叉树的同学们都应该了解,完全二叉 ...

  6. c语言 topk算法,scala写算法-用小根堆解决topK

    topK问题是指从大量数据中获取最大(或最小)的k个数,比如从全校学生中寻找成绩最高的500名学生等等. 本问题可采用小根堆解决.思路是先把源数据中的前k个数放入堆中,然后构建堆,使其保持堆序(可以简 ...

  7. 二叉堆 | 大根堆 小根堆

    目录 何为二叉堆 二叉堆的调整 最大堆 最大堆的插入操作 最大堆的删除操作 最大堆的构建 最大堆code 最小堆 小根堆的插入操作 最小堆的删除操作 最小堆的构建 最小堆code 二叉堆的存储方式 何 ...

  8. 【数据结构】堆,大根堆,小根堆,优先队列 详解

    目录 堆 1.堆的数组实现 2.小根堆 3.大根堆 4.优先队列 例题 1.SP348 EXPEDI - Expedition(有趣的贪心思路,优先队列) 2.合并果子 堆 要了解堆之前,请先了解树, ...

  9. 算法笔记-堆相关、堆的定义、大小根堆、算法程序实现、堆的算法题、C#写法

    内容概述 1,堆结构就是用数组实现的完全二叉树结构 2,完全二叉树中如果每棵子树的最大值都在顶部就是大根堆 3,完全二叉树中如果每棵子树的最小值都在顶部就是小根堆 4,堆结构的heaplnsert与h ...

最新文章

  1. BeanShell中的Java指令和表达式
  2. IBM谢东:2nm芯片可让手机4天一充电,量子计算机大规模应用的未来不会太远|MEET2022...
  3. zhcon解决Ubuntu命令行模式乱码问题
  4. Linux 的文件权限与目录配置
  5. JSON自动生成相关类
  6. Ajax框架,DWR介绍,应用,样例
  7. Docker学习总结(7)——云端基于Docker的微服务与持续交付实践
  8. jQery 操作CSS
  9. java 按顺序读取文件夹_java读取某个文件夹下的所有文件实例代码
  10. 笔试题: 数据库 已看1 一些关键的sql语句练习 和选择题 有用 sql语句练习 挺好...
  11. 181124每日一句
  12. 2018年中国财富管理才真正迎来发展元年
  13. 三思笔记,涂抹ORACLE~~
  14. 数学建模之时间序列分析
  15. java springboot房地产信息管理系统
  16. matlab中非线性误差分析方法,matlab计算方法实验指导误差分析
  17. radio男女选择取值
  18. 极验验证码破解之selenium
  19. 柠檬班性能测试day3_性能测试基础知识(0521)
  20. JVM基础知识整理----体系结构和运行时数据区

热门文章

  1. Educational Codeforces Round 30 A[水题/数组排序]
  2. Mysql 获取年级每个班前十学生的信息
  3. JAVA之旅(五)——this,static,关键字,main函数,封装工具类,生成javadoc说明书,静态代码块...
  4. 北京开源人linux运维实战
  5. LNMT/LAMT实现动静分离、负载均衡和会话保持
  6. Python raw_input 读取输入值 (转载)
  7. Android系统为例解读智能手机如何防盗
  8. javascript的一些基本概念
  9. mongodb备份和恢复:mongodump/mongorestore ( 二)
  10. MySQL介绍及安装(一)