您的位置:首页 > 理论基础 > 计算机网络

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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: