2 回答
TA贡献1900条经验 获得超5个赞
一个Timer的实现需要具备以下几个行为:
StartTimer(Interval, ExpiryAction)
注册一个时间间隔为 Interval 后执行 ExpiryAction 的定时器实例,其中,返回 TimerId 以区分在定时器系统中的其他定时器实例。
StopTimer(TimerId)
根据 TimerId 找到注册的定时器实例并执行 Stop 。
PerTickBookkeeping()
在一个 Tick 时间粒度内,定时器系统需要执行的动作,它最主要的行为,就是检查定时器系统中,是否有定时器实例已经到期。
具体的代码实现思路就是:
在
StartTimer的时候,把 当前时间 + Interval
作为key放入一个容器,然后在Loop的每次Tick里,从容器里面选出一个最小的key与当前时间比较,如果key小于当前时间,则这个key代表的
timer就是expired,需要执行它的ExpiryAction(一般为回调)。
这里有两个实现的细节:
获取当前时间
包含时间精度,使用系统时间还是CPU时间(asio里的deadline_timer和steady_timer的区别)
常用的API是:
Windows: QueryPerformanceFrequency() 和 QueryPerformanceCounter()
Linux: clock_gettime()
OSX: gettimeofday()或者mach_absolute_time()
当然在C++11里也可以偷懒使用chrono的high_resolution_clock std::chrono::high_resolution_clock
2.timer容器的选择
容器应该能够在很短的时间内找到MinValue
最小堆的find-min复杂度是O(1),所以蛮受人喜欢的
STL里提供有堆的API,make_heap, push_heap, pop_heap, sort_heap
3. PerTickBookkeeping是放在主循环线程还是另起线程
另起线程需要做好线程间通信,asio和skynet有单独的timer线程
- 2 回答
- 0 关注
- 1819 浏览
添加回答
举报