基于排序链表的定时器(https://blog.csdn.net/destory27/article/details/81748580)存在一个问题:添加定时器的效率偏低。
如图所示时间轮内,指针指向轮子上的一个槽,它以恒定的速度顺时针旋转,每旋转一步就指向先一个槽.该时间轮共有N个槽,旋转一周的时间是N*Si,每个槽指向一条定时器链表,没条链表上的定时器具有相同的特征:它们的定时时间相差N*Si的整数倍.时间轮正是利用这个关系将定时器散列到不同的链表中。假如现在指针指向槽cs,我们要添加一个定时时间为ti的定时器,则该定时器将被插入槽ts对应的链表: ts = (cs + ti / si) % N.
基于排序链表的定时器使用唯一的一条链表来管理所有的定时器,所有插入操作的效率随着定时器数目的增多而降低.而时间轮使用哈希表思想,将定时器散列到不同的链表上.对于时间轮,要提高定时精度,就要使si值足够小;要提高执行效率,则要求N值足够大.
#ifndef _TIME_WHEEL_TIMER
#define _TIME_WHEEL_TIMER
//时间轮
#include <time.h>
#include <netinet/in.h>
#include <iostream>
#define BUFFER_SIZE 64
class tw_timer; //前向声明
//绑定socket和定时器
struct client_data{
struct sockaddr_in address; //addr
int sockfd;
char buf[BUFFER_SIZE];
tw_timer *timer;
};
/********定时器类*********/
class tw_timer{
public:
tw_timer(int rot, int ts)
:rotation(rot),
time_slot(ts)
{}
void (*cb_func)(client_data *); //定时器回调函数
public:
int rotation; //时间轮转多少圈后生效
int time_slot; //属于时间轮上哪个槽
client_data *user_data{nullptr}; //客户数据
tw_timer *next{nullptr}; //指向下一个定时器
tw_timer *prev{nullptr}; //指向前一个定时器
};
class time_wheel{
public:
time_wheel();
~time_wheel();
tw_timer *add_timer(int timeout); //根据定时值timeout创建一个定时器 插入合适的槽中
void del_timer(tw_timer *timer); //删除目标定时器timer
void tick(); //SI时间到后,调用该函数 时间轮前滚动一个槽的间隔
private:
static const int N = 60; //时间轮上槽的数目
static const int SI = 1; //槽间隔1S
tw_timer *slots[N]; //槽
int cur_slot{0}; //当前槽
};
time_wheel::time_wheel()
{
for(int i = 0; i < N; ++i)
slots[i] = nullptr;
}
time_wheel::~time_wheel()
{
for(int i = 0; i < N; ++i)
{
tw_timer *tmp = slots[i];
while(tmp)
{
slots[i] = tmp->next;
delete tmp;
tmp = slots[i];
}
}