利用红黑树的有序性组织定时事件。由于需要高频的插入和删除,维护红黑树的绝对有序性会带来性能瓶颈,所以该定时器的效率比较一般。(Nginx中的定时器利用红黑树实现)。用小根堆来组织的话,会明显提高插入和删除的的效率,因为它不严格要求有序,维护成本不是太高。比如libevent/libev和golang中的定时器都是用小根堆实现的。
#ifndef TTIMERS_H
#define TTIMERS_H
#include
#include
#ifndef _WIN32
#include
#else
#include
#endif
#include
#include
#include
#include
//typedef void(*Callback)(const struct _TimerNodeBase& node);
struct _TimerNodeBase;
using Callback=std::function;
struct _TimerNodeBase
{
uint64_t expire;
uint64_t offset_expire;
int64_t id;
_TimerNodeBase(int64_t _id, uint64_t _expire) :id(_id), expire(_expire), offset_expire(0){}
bool operator<(const _TimerNodeBase& node) const
{
if (expirenode.expire)
return false;
else
return id locker(time_mx);
if (timeouts.empty() || expire <= timeouts.crbegin()->expire)
{
auto pairs = timeouts.emplace(id, expire, func);
auto iter = pairs.first;
if (pairs.second && iter != timeouts.begin())
{
iter--;
const uint64_t* offset_expire = &pairs.first->offset_expire;
uint64_t* timeoffset = const_cast(offset_expire);
*timeoffset = iter->offset_expire;
}
return static_cast(*pairs.first);
}
auto ele = timeouts.emplace_hint(timeouts.crbegin().base(), id, expire, func);
auto iter = ele;
iter--;
const uint64_t* offset_expire = &ele->offset_expire;
uint64_t* timeoffset = const_cast(offset_expire);
*timeoffset = iter->offset_expire;
return static_cast(*ele);
}
inline bool DelTimer(const _TimerNodeBase& node)
{
struct _TimerNode n(node.id, node.expire, Callback());
time_mx.lock();
auto iter = timeouts.find(n);
if (iter == timeouts.end())
{
time_mx.unlock();
return false;
}
timeouts.erase(iter);
time_mx.unlock();
return true;
}
inline void HandleTimer(uint64_t now)
{
if (paused_markspot>0)
{
TimerSleep(10);
return;
}
time_mx.lock();
auto iter = timeouts.begin();
while (iter != timeouts.end() && (iter->expire + iter->offset_expire <= now))
{
printf("[%lld] execute timer id=%lld.\r\n", now, iter->id);
if (iter->func.operator bool())
{
//如果回调函数很耗时,执行回调期间以下操作将被阻塞:
//AddTimer, DelTimer,StopTimer
//time_mx.unlock();
iter->func(*iter);
//time_mx.lock();
}
iter = timeouts.erase(iter);
continue;
}
time_mx.unlock();
}
inline int TimeToSleep()
{
time_mx.lock();
auto iter = timeouts.begin();
if (iter == timeouts.end())
{
time_mx.unlock();
return -1;
}
int diss = iter->expire + iter->offset_expire - GetCurrentTimeMs();
time_mx.unlock();
return diss>0 ? diss : 0;
}
inline void TimerSleep(int msec)
{
#ifdef _MSC_VER
Sleep(msec);
#else
usleep(1000 * msec);
#endif
}
inline void TimerPause()
{
paused_markspot = GetCurrentTimeMs();
}
inline void TimerResume()
{
if (paused_markspot <= 0)
return;
time_mx.lock();
auto iter = timeouts.begin();
while (iter != timeouts.end())
{
const uint64_t* offset_expire = &iter->offset_expire;
uint64_t* timeoffset = const_cast(offset_expire);
*timeoffset += (GetCurrentTimeMs() - paused_markspot);
iter++;
}
time_mx.unlock();
paused_markspot = 0;
}
inline void TimerStop()
{
time_mx.lock();
auto iter = timeouts.begin();
while (iter != timeouts.end())
{
iter = timeouts.erase(iter);
}
time_mx.unlock();
}
static inline uint64_t GetCurrentTimeMs()
{
#ifndef _MSC_VER
struct timespec ti;
uint64_t t;
clock_gettime(CLOCK_MONOTONIC, &ti);
t = (uint64_t)ti.tv_sec * 1000;
t += ti.tv_nsec / 1000000;
return t;//milliseconds
#else
return GetTickCount64();
#endif
}
private:
static inline int64_t GenID()
{
return gid++;
}
static int64_t gid;
std::atomic_uint64_t paused_markspot = 0;
std::mutex time_mx;
std::set<_TimerNode> timeouts;
};
int64_t Timer::gid = 0;
int main()
{
Timer tim;
tim.AddTimer(1000, [](const _TimerNodeBase& node){
printf("timer expire, node=[id=%lld,expire=%lld, expire_offset=%lld]\r\n", node.id, node.expire, node.offset_expire);
});
const _TimerNodeBase& n = tim.AddTimer(2000, [](const _TimerNodeBase& node){
const _TimerNode& n = static_cast(node);
printf("timer expire, node=[id=%lld,expire=%lld, expire_offset=%lld]\r\n", n.id, n.expire, n.offset_expire);
});
tim.DelTimer(n);
tim.TimerPause();
tim.TimerSleep(2000);
tim.TimerResume();
while (true)
{
int time_sleep = tim.TimeToSleep();
if (time_sleep>0)
tim.TimerSleep(time_sleep);
uint64_t now = Timer::GetCurrentTimeMs();
tim.HandleTimer(now);
}
return 0;
}
#endif
时间轮适用于海量时间密集定时任务。多线程环境下可以做到很小的加锁粒度,效率很高,而红黑树,小根堆以及跳表实现的定时器,对数据操作时都需要将整个结构加锁,效率受限。
linux内核 crontab定时器: 8层时间轮
skynet: 5层时间轮
kafka: 3层时间轮
下面是一个5层时间轮定时器的实现例子,仅供学习参考
//spinlock.h
#ifndef SPINLOCK_H
#define SPINLOCK_H
#include
struct spinlock {
std::atomic_bool flag;
};
void spinlock_init(struct spinlock* lock) {
lock->flag.store(false);
}
void spinlock_lock(struct spinlock* lock) {
bool expected = false;
while (!lock->flag.compare_exchange_weak(expected, true)) {}
//while (__sync_lock_test_and_set(&lock->lock, 1)) {}
}
int spinlock_trylock(struct spinlock* lock) {
bool expected = false;
return lock->flag.compare_exchange_weak(expected, true);
//return __sync_lock_test_and_set(&lock->lock, 1) == 0;
}
void spinlock_unlock(struct spinlock* lock) {
//__sync_lock_release(&lock->lock);
lock->flag.store(false);
}
void spinlock_destroy(struct spinlock* lock) {
(void)lock;
}
#endif
//timerwheel.h
#ifndef __TIMERWHEEL_H__
#define __TIMERWHEEL_H__
#include
#ifndef _MSC_VER
#include
#else
#include
#endif
#define TIME_NEAR_SHIFT 8
#define TIME_NEAR (1 << TIME_NEAR_SHIFT)
#define TIME_NEAR_MASK (TIME_NEAR - 1)
#define TIME_LEVEL_SHIFT 6
#define TIME_LEVEL (1 << TIME_LEVEL_SHIFT)
#define TIME_LEVEL_MASK (TIME_LEVEL - 1)
#define TIME_SCALE 10 //时间精度设为10毫秒
typedef void (*handler_ptr)(void* usrdata, int datalen);
typedef struct timer_node {
uint32_t expire;
handler_ptr callback;
void* data;
int datalen;
uint8_t cancel;
int tid;
} timer_node_t;
timer_node_t* add_timer(int tid,int time, handler_ptr func, void* data, int len,int count=0);
void del_timer(timer_node_t* node);
void expire_timer(void);
void init_timer(void);
void clear_timer(void);
#endif
//timerwheel.cc
#include "spinlock.h"
#include "timerwheel.h"
typedef struct timer_node_internal
{
struct timer_node node;
int count;
int duration;
struct timer_node_internal* next;
}timer_node_it;
typedef struct link_list {
timer_node_it head;
timer_node_it* tail;
} link_list_t;
typedef struct timer {
link_list_t nearest[TIME_NEAR];
link_list_t t[4][TIME_LEVEL];
struct spinlock lock;
uint32_t time_tick;//第一层的时间刻度, 根据时间精度, 每一次加加1(即如果精度为10ms, 则每10ms加1)
uint64_t timestamp_ref;//参考时间戳
} s_timer_t;
static s_timer_t* TI = NULL;
/**
* @brief 移除list下面所有的节点
* @param {link_list_t} *list
* @return {timer_node_it} *ret 节点的链表头
*/
timer_node_it* link_clear(link_list_t* list)
{
timer_node_it* ret = list->head.next;
list->head.next = 0;
list->tail = &(list->head);
return ret;
}
void link(link_list_t* list, timer_node_it* node)
{
list->tail->next = node;
list->tail = node;
node->next = 0;
}
void add_node(s_timer_t* T, timer_node_it* node)
{
uint32_t time = node->node.expire;
uint32_t current_time = T->time_tick;
uint32_t msec = time - current_time;
if (msec < TIME_NEAR) { //[0, 0x100)
link(&T->nearest[time & TIME_NEAR_MASK], node);
}
else if (msec < (1 << (TIME_NEAR_SHIFT + TIME_LEVEL_SHIFT))) { //[0x100, 0x4000)
link(&T->t[0][((time >> TIME_NEAR_SHIFT) & TIME_LEVEL_MASK)], node);
}
else if (msec < (1 << (TIME_NEAR_SHIFT + 2 * TIME_LEVEL_SHIFT))) { //[0x4000, 0x100000)
link(&T->t[1][((time >> (TIME_NEAR_SHIFT + TIME_LEVEL_SHIFT)) & TIME_LEVEL_MASK)], node);
}
else if (msec < (1 << (TIME_NEAR_SHIFT + 3 * TIME_LEVEL_SHIFT))) { //[0x100000, 0x4000000)
link(&T->t[2][((time >> (TIME_NEAR_SHIFT + 2 * TIME_LEVEL_SHIFT)) & TIME_LEVEL_MASK)], node);
}
else { //[0x4000000, 0xffffffff]
link(&T->t[3][((time >> (TIME_NEAR_SHIFT + 3 * TIME_LEVEL_SHIFT)) & TIME_LEVEL_MASK)], node);
}
}
/**
* @brief 从timer子数组(level)取出idx的链表节点, 并重新添加到timer中
* @param {s_timer_t} *T
* @param {int} level
* @param {int} idx
* @return {*}
*/
void move_list(s_timer_t* T, int level, int idx)
{
timer_node_it* current = link_clear(&T->t[level][idx]);
while (current) {
timer_node_it* temp = current->next;
add_node(T, current);
current = temp;
}
}
/**
* @brief 重新映射, 将该层时间节点下的链表重新映射到上一层去
* @param {s_timer_t} *T
* @return {*}
*/
void timer_shift(s_timer_t* T)
{
int mask = TIME_NEAR;
uint32_t ct = ++T->time_tick;
if (ct == 0) {
move_list(T, 3, 0);
}
else {
// ct / 256
uint32_t time = ct >> TIME_NEAR_SHIFT;
int i = 0;
// ct % 256 == 0
while ((ct & (mask - 1)) == 0) {
int idx = time & TIME_LEVEL_MASK;
if (idx != 0) {
move_list(T, i, idx);
break;
}
mask <<= TIME_LEVEL_SHIFT;
time >>= TIME_LEVEL_SHIFT;
++i;
}
}
}
/**
* @brief 执行所有节点的回调
* @param {timer_node_it} *current
* @return {*}
*/
void dispatch_list(s_timer_t* T,timer_node_it* current)
{
do {
timer_node_it* temp = current;
current = current->next;
if (temp->node.cancel == 0) {
temp->node.callback(temp->node.data,temp->node.datalen);
}
if (temp->node.cancel != 0)
{
free(temp);
continue;
}
if (temp->count < 0||--temp->count>0)
{
temp->next = NULL;
temp->node.expire = temp->duration + T->time_tick;
spinlock_lock(&T->lock);
add_node(T, temp);
spinlock_unlock(&T->lock);
}
else
{
free(temp);
}
} while (current);
}
void timer_execute(s_timer_t* T)
{
int idx = T->time_tick & TIME_NEAR_MASK;
while (T->nearest[idx].head.next) {
timer_node_it* current = link_clear(&T->nearest[idx]);
spinlock_unlock(&T->lock);
dispatch_list(T,current);
spinlock_lock(&T->lock);
}
}
/**
* @brief 更新定时器
* @param {s_timer_t} *T
* @return {*}
*/
void timer_update(s_timer_t* T)
{
spinlock_lock(&T->lock);
timer_execute(T);
timer_shift(T);
timer_execute(T);
spinlock_unlock(&T->lock);
}
s_timer_t* timer_create_timer(void)
{
s_timer_t* timer = (s_timer_t*)malloc(sizeof(s_timer_t));
memset(timer, 0, sizeof(s_timer_t));
int i, j;
for (i = 0; i < TIME_NEAR; i++) {
link_clear(&timer->nearest[i]);
}
for (i = 0; i < sizeof(timer->t) / sizeof(timer->t[0]); i++) {
for (j = 0; j < TIME_LEVEL; j++) {
link_clear(&timer->t[i][j]);
}
}
spinlock_init(&timer->lock);
return timer;
}
uint64_t get_current_time(void)
{
#ifndef _MSC_VER
struct timespec ti;
uint64_t t;
clock_gettime(CLOCK_MONOTONIC, &ti);
t = (uint64_t)ti.tv_sec * 1000;
t += ti.tv_nsec / 1000000;//milliseconds
return t/TIME_SCALE;
#else
return GetTickCount64()/ TIME_SCALE;
#endif
}
/**
* @brief 添加定时任务
* @param {int} threadid
* @param {int} time delayed
* @param {handler_pt} func
* @param {void*} user data
* @param {int} data len
* @param {int} task count, default 0 means oneshot executing, negiative value means endless executing.
* @return {timer_node_t*}
*/
timer_node_t* add_timer(int tid,int time, handler_ptr func, void* data, int len,int count)
{
timer_node_it* node = (timer_node_it*)malloc(sizeof(timer_node_it));
spinlock_lock(&TI->lock);
node->node.expire = time + TI->time_tick;
node->node.callback = func;
node->node.data = data;
node->node.datalen = len;
node->node.tid = tid;
node->node.cancel = 0;
node->count = count;
node->duration = time;
node->next = NULL;
if (time <= 0) {
node->node.callback(node->node.data,node->node.datalen);
free(node);
spinlock_unlock(&TI->lock);
return NULL;
}
add_node(TI, node);
spinlock_unlock(&TI->lock);
return &node->node;
}
/**
* @brief 取消定时任务
* @param {timer_node_t} *node
* @return {*}
*/
void del_timer(timer_node_t* node)
{
node->cancel = 1;
}
/**
* @brief 遍历定时器, 并执行过期的定时器回调
* @param {*}
* @return {*}
*/
void expire_timer(void)
{
uint64_t cp = get_current_time();
if (cp != TI->timestamp_ref) {
uint32_t diff = (uint32_t)(cp - TI->timestamp_ref);
TI->timestamp_ref = cp;
int i;
for (i = 0; i < diff; i++) {
timer_update(TI);
}
}
}
void init_timer(void)
{
TI = timer_create_timer();
TI->timestamp_ref = get_current_time();
}
void clear_timer(void)
{
int i, j;
for (i = 0; i < TIME_NEAR; i++) {
link_list_t* list = &TI->nearest[i];
timer_node_it* current = list->head.next;
while (current) {
timer_node_it* temp = current;
current = current->next;
free(temp);
}
link_clear(&TI->nearest[i]);
}
for (i = 0; i < sizeof(TI->t) / sizeof(TI->t[0]); i++) {
for (j = 0; j < TIME_LEVEL; j++) {
link_list_t* list = &TI->t[i][j];
timer_node_it* current = list->head.next;
while (current) {
timer_node_it* temp = current;
current = current->next;
free(temp);
}
link_clear(&TI->t[i][j]);
}
}
}
//main.cc
#include "timerwheel.h"
#include
#include
#include
static int temp_flag = 0;
void timer_func_cb(void* data, int len)
{
temp_flag--;
printf("+++ data address=%#x,data length=%d\n",data,len);
}
int main()
{
printf("+++ func: %s, line: %d +++\n", __FUNCTION__, __LINE__);
init_timer();
timer_node_t* delay_task = add_timer(100,600, timer_func_cb,NULL,0,-1);
temp_flag = 3;
while (temp_flag) {
expire_timer();
std::this_thread::sleep_for(std::chrono::microseconds(200));//休眠时间要小于时间精度(10ms),因为每个定时事件的处理也需要消耗一定的时间
}
printf("+++ func: %s, line: %d +++\n", __FUNCTION__, __LINE__);
clear_timer();
return 0;
}