时间轮定时器

基础数据结构:

event_type _type;          // 类型
uint64_t _index;           // guid(时间戳)
uint32_t _repeat;          // 重复次数
timer_callback _caller;    // 回调

时间轮结构定义:

union timer_clock
{
    time64_t time;
    struct
    {
        uint32_t m5 : 10;
        uint32_t m4 : 8;
        uint32_t m3 : 6;
        uint32_t m2 : 6;
        uint32_t m1 : 6;
        uint32_t m0 : 6;
    };
};

桶名最大容纳容器起始位置
m510240x000
m42560x400
m3640x500
m2640x540
m1640x580
m0640x5c0

自内向外依次是m5、m4、m3、m2、m1、m0

认为m5是最小的桶,m0是最大的桶

Mgr数据成员:

std::vector<std::list<time64_t> > _wheelVec;
std::unordered_map<time64_t, timer_event> _timeSeq2Evt;
time64_t _timeSeconds;       // 时间轮精度下的当前时间戳

insert:

当前有两个时间戳,一个是数据成员 _timeSeconds,另一个是insert的事件下次要触发的时间戳 deadline,将这两个时间转化为timer_clock类型,确定事件在时间轮里面的位置

if( t1.m0 != t2.m0 )
{
    _wheelVec[0x5c0 + t1.m0].push_back(_handle);
}
else if( t1.m1 != t2.m1 )
{
    _wheelVec[0x580 + t1.m1].push_back(_handle);
}
else if( t1.m2 != t2.m2 )
{
    _wheelVec[0x540 + t1.m2].push_back(_handle);
}
else if( t1.m3 != t2.m3 )
{
    _wheelVec[0x500 + t1.m3].push_back(_handle);
}
else if( t1.m4 != t2.m4 )
{
    _wheelVec[0x400 + t1.m4].push_back(_handle);
}
else
{
    _wheelVec[t1.m5].push_back(_handle);
}

_handle是一个唯一索引,也就是 _timeSeq2Evt 的 key

接下来是执行:

timer_clock now; // ... 赋值当前时间戳(以时间轮的精度)

while( _timeSeconds <= now.time )
{
	timer_clock ts = { tickcount_ };

	if( ts.m5 )
	{
		_clock_step_list( time_wheel_[ts.m5] );
	}
	else if( ts.m4 )
	{
		_clock_step_list( _wheelVec[ts.m4 + 0x400] );
	}
	else if( ts.m3 )
	{
		_clock_step_list( _wheelVec[ts.m3 + 0x500] );
	}
	else if( ts.m2 )
	{
		_clock_step_list( _wheelVec[ts.m2 + 0x540] );
	}
	else if( ts.m1 )
	{
		_clock_step_list( _wheelVec[ts.m1 + 0x580] );
	}
	else if( ts.m0 )
	{
		_clock_step_list( _wheelVec[ts.m0 + 0x5c0] );
	}

	_timeSeconds += 1;
}
return true;
_clock_step_list的入参是一个list的引用(后面需要clear这个list),这个函数需要做的就是检查时间,如果时间 <= _timeSeconds 就调用 _caller 执行,否则,重新insert_clock(这个操作其实就是把外层的事件move到内层去),遍历完整个list,做一个clear


存在的问题是如果测试期间修改服务器时间,定时器会循环很多次处理事件,可能引起网络的超时断链,cpu跑满等问题,可以考虑增加一个判断,如果循环超过2000次break一次,其他的等下次主循环跑到了再执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值