Linux网络编程--定时器之时间轮
2016-03-10 15:29
549 查看
由于基于升序定时器链表的添加定时器效率偏低,所以本博文介绍一种高效的定时器---时间轮;
时间轮:包含时间间隔si,时间轮槽数N,运行一周所用的时间是si*N。每一个槽就是一个无序的定时器链表,并且拥有统一的特征,定时时间相差N*si整数倍。
时间轮的优势在于采用哈希表的思想,将定时器散列在不同的定时器链表中,这样插入定时器的效率不受定时器数目影响。
那么很显然,要提高定时精度,si值越小越好;要提高执行效率,N的值越大越好。
下面使用代码介绍一种简单的时间轮,简单是因为只有一个轮子。当然我们可以使用很多轮子,例如水表、机械手表模型;
<span style="font-size:14px;">#ifndef TIME_WHEEL_TIMER
#define TIME_WHEEL_TIMER
#include <time.h>
#include <netinet/in.h>
#include <stdio.h>
#define BUFFER_SIZE 64
class tw_timer;
struct client_data//用户数据结构
{
sockaddr_in address;
int sockfd;
char buf[ BUFFER_SIZE ];
tw_timer* timer;
};
class tw_timer//定时器结构
{
public:
tw_timer( int rot, int ts )
: next( NULL ), prev( NULL ), rotation( rot ), time_slot( ts ){}
public:
int rotation;//记录定时器在时间轮转多少圈生效
int time_slot;//记录定时器属于哪一个槽(也就是哪一个链表)
void (*cb_func)( client_data* );//回调函数 同上
client_data* user_data;//用户数据
tw_timer* next;
tw_timer* prev;
};
class time_wheel
{
public:
time_wheel() : cur_slot( 0 )
{
for( int i = 0; i < N; ++i )
{
slots[i] = NULL;
}
}
~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];
}
}
}
tw_timer* add_timer( int timeout )
{
if( timeout < 0 )
{
return NULL;
}
int ticks = 0;
if( timeout < TI )
{
ticks = 1;
}
else
{
ticks = timeout / TI;
}
int rotation = ticks / N;
int ts = ( cur_slot + ( ticks % N ) ) % N;
tw_timer* timer = new tw_timer( rotation, ts );
if( !slots[ts] )
{
printf( "add timer, rotation is %d, ts is %d, cur_slot is %d\n", rotation, ts, cur_slot );
slots[ts] = timer;
}
else
{
timer->next = slots[ts];
slots[ts]->prev = timer;
slots[ts] = timer;
}
return timer;
}
void del_timer( tw_timer* timer )
{
if( !timer )
{
return;
}
int ts = timer->time_slot;
if( timer == slots[ts] )
{
slots[ts] = slots[ts]->next;
if( slots[ts] )
{
slots[ts]->prev = NULL;
}
delete timer;
}
else
{
timer->prev->next = timer->next;
if( timer->next )
{
timer->next->prev = timer->prev;
}
delete timer;
}
}
void tick()
{
tw_timer* tmp = slots[cur_slot];
printf( "current slot is %d\n", cur_slot );
while( tmp )
{
printf( "tick the timer once\n" );
if( tmp->rotation > 0 )
{
tmp->rotation--;
tmp = tmp->next;
}
else
{
tmp->cb_func( tmp->user_data );
if( tmp == slots[cur_slot] )
{
printf( "delete header in cur_slot\n" );
slots[cur_slot] = tmp->next;
delete tmp;
if( slots[cur_slot] )
{
slots[cur_slot]->prev = NULL;
}
tmp = slots[cur_slot];
}
else
{
tmp->prev->next = tmp->next;
if( tmp->next )
{
tmp->next->prev = tmp->prev;
}
tw_timer* tmp2 = tmp->next;
delete tmp;
tmp = tmp2;
}
}
}
cur_slot = ++cur_slot % N;
}
private:
static const int N = 60;//时间轮槽的数目N
static const int TI = 1; //时间轮时间间隔si,1秒
tw_timer* slots
;
int cur_slot;//当前槽位置
};
#endif
</span>
时间轮:包含时间间隔si,时间轮槽数N,运行一周所用的时间是si*N。每一个槽就是一个无序的定时器链表,并且拥有统一的特征,定时时间相差N*si整数倍。
时间轮的优势在于采用哈希表的思想,将定时器散列在不同的定时器链表中,这样插入定时器的效率不受定时器数目影响。
那么很显然,要提高定时精度,si值越小越好;要提高执行效率,N的值越大越好。
下面使用代码介绍一种简单的时间轮,简单是因为只有一个轮子。当然我们可以使用很多轮子,例如水表、机械手表模型;
<span style="font-size:14px;">#ifndef TIME_WHEEL_TIMER
#define TIME_WHEEL_TIMER
#include <time.h>
#include <netinet/in.h>
#include <stdio.h>
#define BUFFER_SIZE 64
class tw_timer;
struct client_data//用户数据结构
{
sockaddr_in address;
int sockfd;
char buf[ BUFFER_SIZE ];
tw_timer* timer;
};
class tw_timer//定时器结构
{
public:
tw_timer( int rot, int ts )
: next( NULL ), prev( NULL ), rotation( rot ), time_slot( ts ){}
public:
int rotation;//记录定时器在时间轮转多少圈生效
int time_slot;//记录定时器属于哪一个槽(也就是哪一个链表)
void (*cb_func)( client_data* );//回调函数 同上
client_data* user_data;//用户数据
tw_timer* next;
tw_timer* prev;
};
class time_wheel
{
public:
time_wheel() : cur_slot( 0 )
{
for( int i = 0; i < N; ++i )
{
slots[i] = NULL;
}
}
~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];
}
}
}
tw_timer* add_timer( int timeout )
{
if( timeout < 0 )
{
return NULL;
}
int ticks = 0;
if( timeout < TI )
{
ticks = 1;
}
else
{
ticks = timeout / TI;
}
int rotation = ticks / N;
int ts = ( cur_slot + ( ticks % N ) ) % N;
tw_timer* timer = new tw_timer( rotation, ts );
if( !slots[ts] )
{
printf( "add timer, rotation is %d, ts is %d, cur_slot is %d\n", rotation, ts, cur_slot );
slots[ts] = timer;
}
else
{
timer->next = slots[ts];
slots[ts]->prev = timer;
slots[ts] = timer;
}
return timer;
}
void del_timer( tw_timer* timer )
{
if( !timer )
{
return;
}
int ts = timer->time_slot;
if( timer == slots[ts] )
{
slots[ts] = slots[ts]->next;
if( slots[ts] )
{
slots[ts]->prev = NULL;
}
delete timer;
}
else
{
timer->prev->next = timer->next;
if( timer->next )
{
timer->next->prev = timer->prev;
}
delete timer;
}
}
void tick()
{
tw_timer* tmp = slots[cur_slot];
printf( "current slot is %d\n", cur_slot );
while( tmp )
{
printf( "tick the timer once\n" );
if( tmp->rotation > 0 )
{
tmp->rotation--;
tmp = tmp->next;
}
else
{
tmp->cb_func( tmp->user_data );
if( tmp == slots[cur_slot] )
{
printf( "delete header in cur_slot\n" );
slots[cur_slot] = tmp->next;
delete tmp;
if( slots[cur_slot] )
{
slots[cur_slot]->prev = NULL;
}
tmp = slots[cur_slot];
}
else
{
tmp->prev->next = tmp->next;
if( tmp->next )
{
tmp->next->prev = tmp->prev;
}
tw_timer* tmp2 = tmp->next;
delete tmp;
tmp = tmp2;
}
}
}
cur_slot = ++cur_slot % N;
}
private:
static const int N = 60;//时间轮槽的数目N
static const int TI = 1; //时间轮时间间隔si,1秒
tw_timer* slots
;
int cur_slot;//当前槽位置
};
#endif
</span>
相关文章推荐
- 网络基础知识1
- http://www.dewen.net.cn/q/16007/mysql查询如何先排序再分组呢
- http://www.dewen.net.cn/q/16042/jquery fadeIn和fadeOut问题
- http://www.dewen.net.cn/q/17095/SQL:用一条SQL语句统计出符合条件的内容
- http://www.dewen.net.cn/q/16222/C++排序中的sort函数第三个参数的疑问
- TCP/IP协议 1 ----实验楼转
- http://www.dewen.net.cn/q/15720/这样的情况一个sql语句怎么写
- 打造平安城市精品视频监控网络
- 浅谈HTTP中Get与Post的区别
- 使用802.1X+FreeRadius+LDAP实现网络准入方案
- node.js基础模块http、网页分析工具cherrio实现爬虫
- 判断安卓设备是否连接网络
- http 500错误详细代码意义
- iOS开发网络篇—数据缓存
- 关于HttpClient(调用openstack rest接口失败)
- TCP三次握手,四次挥手的状态变化
- Unity: C# TCP Client Server TcpListener NetworkStream UDP
- 【Android】【xUtils3网络下载图片的简单操作】
- Bitnami-Redmine通过https远程连接svn
- 可扩展,兼容多种网络请求框架的方案!!!