基于Libevent最小根堆定时器的C++定时器实现
2016-01-14 17:51
549 查看
在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 */
相关文章推荐
- 欢迎使用CSDN-markdown编辑器
- C++ 学习
- 详解C++编程中的主表达式与后缀表达式编写基础
- setjmp和longjmp解析
- C++ socket传输结构体
- treap 1286郁闷的出纳员.cpp
- C++引用
- 关于C++中用两个迭代器方式初始化string的知识
- C++调用java的过程
- C/C++动态分配与释放内存的区别详细解析
- Google C++ 编程规范 笔记
- 【C语言】有一个字符数组的内容为:"student a am i",请你将数组的内容改为"i am a student".
- 并查集_POJ 1182_食物链
- c/c++宏定义的基本用法
- 讲解C++编程中Address-of运算符&的作用及用法
- c语言实现动态指针数组Dynamic arrays
- C语言练习代码
- C语言技巧
- C语言 随机数
- 详解C++编程中的sizeof运算符与typeid运算符