#include "TimerAxis.h"
//////////////////////////////////////////////////////////////////////////
TimerAxis::TimerAxis()
{
m_TimerAxis.resize((TIME_AXIS_LENGTH + TIME_GRID - 1) / TIME_GRID);
m_dwInitializeTime = GetTickCount();
m_dwLastCheckTick = m_dwInitializeTime;
m_dwCurRunTime = m_dwInitializeTime;
m_dwTimerCount = 0;
}
//////////////////////////////////////////////////////////////////////////
TimerAxis::~TimerAxis()
{
for (uint32_t i = 0; i<m_TimerAxis.size(); ++i)
{
TIMER_LIST & TimerList = m_TimerAxis[i];
TIMER_LIST::iterator it = TimerList.begin();
for (; it != TimerList.end(); ++it)
{
Timer* timer = *it;
if (timer)
{
KillTimer(timer->dwTimerID, timer->handler);
}
}
}
m_TimerAxis.clear();
}
int TimerAxis::Run(uint64_t lTime)
{
CheckTimer();
return 0;
}
//////////////////////////////////////////////////////////////////////////
bool TimerAxis::SetTimer(uint32_t timerID, uint32_t interval, ITimerHandler * handler, uint32_t calltimes, const char * debugInfo)
{
if (handler == 0)
{
return false;
}
if (interval == 0)
{
interval = 1;
}
void** ppTimerInfo = handler->GetTimerInfoPtr();
TIMER_INFO* pTimerInfo = *(TIMER_INFO**)ppTimerInfo;
if (pTimerInfo == NULL)
{
pTimerInfo = new TIMER_INFO;
*ppTimerInfo = pTimerInfo;
}
// 检查是否已经添加了这个Timer
TIMER_INFO::iterator it = pTimerInfo->begin();
for (; it != pTimerInfo->end(); ++it)
{
Timer & timer = *it;
if (timer.dwTimerID == timerID)
{
return false;
}
}
Timer timer;
timer.dwTimerID = timerID;
timer.dwInterval = interval;
timer.dwCallTimes = calltimes;
timer.dwLastCallTick = m_dwCurRunTime;//m_dwLastCheckTick;
timer.handler = handler;
#ifdef SUPPORT_TIMEAXIS_DEBUG_INFO
if (debugInfo) timer.debugInfo = debugInfo;
#endif
timer.dwGridIndex = ((timer.dwLastCallTick + timer.dwInterval - m_dwInitializeTime) / TIME_GRID) % m_TimerAxis.size();
pTimerInfo->push_back(timer);
Timer & timerRef = pTimerInfo->back();
Timer * timerPtr = &timerRef;
m_TimerAxis[timer.dwGridIndex].push_back(timerPtr);
timerPtr->pos = --m_TimerAxis[timer.dwGridIndex].end();
++m_dwTimerCount;
//printf("TimerAxis::SetTimer(), timerID=%d, dwLastCallTick=%d, interval=%d, gridIndex=%d, m_dwTimerCount=%d \n", timerID, timer.dwLastCallTick, interval, timer.dwGridIndex, m_dwTimerCount);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool TimerAxis::KillTimer(uint32_t timerID, ITimerHandler * handler)
{
void ** ppTimerInfo = handler->GetTimerInfoPtr();
TIMER_INFO * pTimerInfo = *(TIMER_INFO **)ppTimerInfo;
// 根本就没添加
if (pTimerInfo == 0)
return false;
// 检查是否已经添加了这个Timer
TIMER_INFO::iterator it = pTimerInfo->begin();
for (; it != pTimerInfo->end(); ++it)
{
Timer & timer = *it;
if (timer.dwTimerID == timerID)
{
*timer.pos = 0;
pTimerInfo->erase(it);
if (pTimerInfo->empty())
{
delete pTimerInfo;
*ppTimerInfo = 0;
}
--m_dwTimerCount;
return true;
}
}
return false;
}
void TimerAxis::KillTimer(ITimerHandler* handler)
{
void** ppTimerInfo = handler->GetTimerInfoPtr();
TIMER_INFO* pTimerInfo = *(TIMER_INFO**)ppTimerInfo;
// 根本就没添加
if (pTimerInfo == 0)
return;
// 检查是否已经添加了这个Timer
TIMER_INFO::iterator it = pTimerInfo->begin();
for (; it != pTimerInfo->end(); ++it)
{
Timer& timer = *it;
*timer.pos = 0;
--m_dwTimerCount;
}
// clear and delete
pTimerInfo->clear();
delete pTimerInfo;
*ppTimerInfo = 0;
}
//////////////////////////////////////////////////////////////////////////
void TimerAxis::CheckTimer(uint64_t timeout)
{
uint64_t now = GetTickCount();
if (now - m_dwLastCheckTick < CHECK_FREQUENCY)
return;
uint32_t dwSizes = m_TimerAxis.size();
if (dwSizes == 0)
return;
uint32_t start_grid = ((m_dwLastCheckTick - m_dwInitializeTime) / TIME_GRID) % dwSizes;
uint32_t cur_grid = ((now - m_dwInitializeTime) / TIME_GRID) % dwSizes;
uint32_t i = start_grid;
// 遍历时间刻度
do
{
m_dwCurRunTime = GetTickCount();
// 遍历当前时间刻度中的所有待触发定时器
TIMER_LIST & TimerList = m_TimerAxis[i];
TIMER_LIST::iterator it = TimerList.begin();
for (; it != TimerList.end();)
{
Timer * timer = *it;
if (timer == 0)
{
it = TimerList.erase(it);
continue;
}
//Debug("TimerAxis::CheckTimer(), timer.dwTimerID=%d, timer.dwLastCallTick=%d, timer.dwInterval=%d", timer->dwTimerID, timer->dwLastCallTick, timer->dwInterval)
// 触发定时器
if (now - timer->dwLastCallTick >= timer->dwInterval)
{
int nTick = GetTickCount();
// 整个函数执行时间过长,需要让出CPU给其他人执行
if (timeout != 0 && (uint32_t)nTick > timeout + now)
{
if (i > start_grid)
{
m_dwLastCheckTick += (i - start_grid) * TIME_GRID;
}
else if (i<start_grid && i + dwSizes>start_grid) // 回绕了
{
m_dwLastCheckTick += (i + dwSizes - start_grid) * TIME_GRID;
}
return;
}
// 回调
timer->handler->OnTimer(timer->dwTimerID);
// 检查一下这个Timer是否被删除了
if (*it == timer)
{
// 性能测试代码
int nCostTime = GetTickCount() - nTick;
if (nCostTime > 64)
{
#ifdef SUPPORT_TIMEAXIS_DEBUG_INFO
printf("Timer low performance: id=%d interval=%d cost=%d %s \n", timer->dwTimerID, timer->dwInterval, nCostTime, timer->debugInfo.c_str());
#else
printf("Timer low performance: id=%d interval=%d cost=%d \n", timer->dwTimerID, timer->dwInterval, nCostTime);
#endif
}
// 用GetTickCount()不用now的好处就是如果CPU很卡,则时间轴会递推,比如CheckTimer只能1秒调用一次,
// 如果<10毫秒的定时器用now搬运的话将被调用100次,无疑加大了程序负担,但用now能保证逻辑更正确
// 用m_dwCurRunTime替代GetTickCount()的意义是在同一个桶中的节点不要因为先后执行的顺序被挪得很乱
timer->dwLastCallTick = timeout == 0 ? now : m_dwCurRunTime;
timer->dwCallTimes -= 1;
if (timer->dwCallTimes == 0)
{
// 调用次数已经够了
KillTimer(timer->dwTimerID, timer->handler);
}
else
{
// 搬迁到下一次触发的位置
timer->dwGridIndex = ((timer->dwLastCallTick + timer->dwInterval - m_dwInitializeTime) / TIME_GRID) % dwSizes;
it = TimerList.erase(it);
m_TimerAxis[timer->dwGridIndex].push_back(timer);
timer->pos = --m_TimerAxis[timer->dwGridIndex].end();
continue;
}
}
else
{
// timer自己被删除了
it = TimerList.erase(it);
continue;
}
}
++it;
}
// 递进到下一个刻度
if (i == cur_grid)
break;
i = (i + 1) % dwSizes;
} while (i != cur_grid);
// 这句不能掉
m_dwLastCheckTick = now;
}
ITimerHandler::~ITimerHandler()
{
TimerAxis* ta = TimerAxis::Instance();
if (ta)
{
ta->KillTimer(this);
}
}
TimerAxis.rar
需积分: 9 193 浏览量
2019-11-17
22:28:27
上传
评论 2
收藏 8.21MB RAR 举报
YZF_Kevin
- 粉丝: 4485
- 资源: 54
最新资源
- 基于STM32F103C8T6单片机蓄电池在线监测系统主板硬件(原理图+PCB)工程文件.zip
- mysql大纲资料.txt
- c++大纲资料.txt
- 效率工具bat脚本实现日志提取
- MyBatis 中动态 SQL 的示例
- STM8L101F3P6单片机+CC1100模块433M遥控器设计硬件(原理图+PCB)工程文件.zip
- 上传下载铁人下载系统 Liuxing 1.0-liuxing1.0.rar
- 南京邮电大学数学实验实力雄厚,凭借其优秀的师资力量、丰富的实践教学资源和卓越的科研成果,成为国内一流的数学实验教学和科研基地
- 【火爆朋友圈的今天吃什么源码 v1.0】随机的为用户带来每一天的用餐选择和推荐.rar
- MPU6050中文版数据手册
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈