已经好几天没有写博客了。
这几天都在看定时器,想搞清楚他的原理,想知道他到底是怎么用的。无奈没有一篇能够比较系统地告诉我定时器是干什么的,怎么用的,导致项目长时间停滞。
在看了几篇博客之后,根据我自己的理解,实现了一个简单的定时器,其中有参考其他的博文的写法,好在我现在实现了一个看起来能用的定时器。
定时器的应用场景
场景一:keep alive保活机制
成千上万个客户端去连接一台聊天服务器,那么就会存在成千上万个tcp连接。但是这些tcp连接是每时每刻都保持发包收包的活跃状态吗?不是!
某些tcp连接上,可能建立之后,在一天之内就没再发包/收包过,为了把有限的系统资源分配给更活跃的用户使用,我们应该设计一种方案来踢掉空闲连接。
场景二:游戏中,指定时间(或间隔时间)执行某种特定操作
-
每日/每周/每月,特定时间执行一次操作
-
循环执行的定时器,比如每隔一分钟刷新一次野怪
-
只执行一次的定时器,在60秒后定时器超期,执行操作A
各种定时器性能比较
实现方式 | StartTimer | StopTimer | PerTickBookkeeping |
---|---|---|---|
基于排序的链表 | O(n) | O(1) | O(1) |
基于最小堆 | O(logn) | O(1) | O(1) |
基于时间轮 | O(1) | O(1) | O(1) |
具体实现
这里采用了最小堆实现
Timer_mng.h
#ifndef __TIMER_MNG_
#define __TIMER_MNG_
#define ull unsigned long long
#define __INF__ 1e18
using namespace std;
enum t_type {
ONCE,CIRCLE};
class Timer_mng;
class Timer;
struct Heap_entry{
//堆条目
unsigned long long time;
Timer *timer;
};
struct Timer{
t_type ttype; //任务类型,一次还是循环
void *(*run)(void *args); //回调函数
void *arg; //会调函数参数
ull itvl; //时间片长度(ms)
ull expires; //到期时间
int heapIndex; //在堆中的下标
Timer(); //初始化
void Start(void *(*run)(void *args),void *arg,ull itvl, t_type ttype);
void OnTimer(); //无剩余时间
};
struct Timer_mng{
vector<Heap_entry*>heap; //堆
~Timer_mng(); //析构函数
void DetectTimers(); //检测是否超时
void AddTimer(Timer* timer); //向堆中添加一个定时器
void RemoveTimer(Timer* timer); //移除定时器
void UpHeap(int idx); //堆操作,向上更新
void DownHeap(int idx); //堆操作,向下更新
void SwapHeap(int idx1, int idx2); //更换堆中的两个元素
};
ull Get_now(); //得到当前时间(ms)
#endif
Timer_mng.cpp
#