对于游戏编程来说,timer是绝对不陌生的,不过以前一直使用一些库提供的timer,像sdl的timer,windows api提供的timer,这段时间突然觉得像这种东西还是在自己的游戏引擎里面实现一个,作为基本类库使用。
首先参考了一下linux的timer机制,详细见 http://www.linuxforum.net/forum/showthreaded.php?Cat=&Board=driver&Number=385224&page=0&view=collapsed&sb=5&o=all&vc=1
不过我实现的跟这个还是有点不一样的。
主要思想就是采用一个timer wheel,假设有一个timer的循环队列,队列上面的每个对象(我们叫做slot)是一个timer的list,现在我们处理到了第m轮第n个slot上面,这时候注册了一个timer,这个timer的间隔为interval毫秒,那么这个timer就应该放到第 n + interval / timer_interval (timer_interval为定时器的精度时间)的slot上面,然后挂在到该slot对应的list末尾,因为我们的环有长度,所以如果注册的timer interval时间很长,interval / timer_interval + n可能超出了wheel的长度,不过由于我们是一个环状结构,所以我们这个timer会在第 m + interval % timer_interval轮之后运行,同时是放到 (n + interval / timer_interval) % max_slotnum这个slot上面。
注册完成以后,当我们的处理到相应的slot的上面的时候,我们会一次的从list上面取出timer,然后现判断是否该timer是在该轮运行,不是则不处理,是则处理。如果碰到interval为0的timer,则会一直处理,知道该timer自己删除自己。
另外,由于我们的定时器有一个最小精度,所以除了interval为0的以外,其他的小于timer_interval的时间,我们全认为是timer_interval。
这个timer实现的非常简单,而且只能保证精度为timer_interval(一般也就是30ms),不过对于我来说,已经够了。
下面帖代码。
/**********************************************/
//BaseType.h
/**********************************************/
#pragma once
typedef char int8;
typedef short int16;
typedef int int32;
typedef long long int;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long long uint;
/**********************************************/
//CTimer.h
/**********************************************/
#pragma once
#include "BaseType.h"
#include <list>
class CTimer
{
friend class CTimerMgr;
public:
CTimer();
~CTimer();
virtual void OnTimer();
private:
uint32 m_uInterval; //timer的间隔时间
uint32 m_uRing; //第几轮运行
std::list<CTimer*>* m_pTimerList; //在当前哪个mgr list上面
std::list<CTimer*>::iterator m_itInList; //在timer list上面对应的iteratoro
};
/**********************************************/
//CTimer.cpp
/**********************************************/
#include "CTimer.h"
#include <list>
using namespace std;
CTimer::CTimer()
: m_pTimerList(NULL),
m_uInterval(0),
m_uRing(0)
{
}
CTimer::~CTimer()
{
if(m_pTimerList)
m_pTimerList->erase(m_itInList);
}
void CTimer::OnTimer()
{
}
/**********************************************/
//CTimerMgr.h
/**********************************************/
#pragma once
#include "BaseType.h"
#include <vector>
#include <list>
class CTimer;
class CTimerMgr
{
friend class CTimer;
public:
CTimerMgr(uint32 uInterval, uint32 uSlotNum);
~CTimerMgr();
void RegisterTimer(CTimer* pTimer, uint32 uInterval);
void UnRegisterTimer(CTimer* pTimer);
void OnTimer();
private:
std::vector<std::list<CTimer*>* > m_vecTimerContainer;
uint32 m_uInterval;
uint32 m_uSlotNum;
uint32 m_uRing;
uint32 m_uCurSlot;
};
/**********************************************/
//CTimerMgr.cpp
/**********************************************/
#include "CTimerMgr.h"
#include "CTimer.h"
#include <vector>
#include <list>
#include <assert.h>
using namespace std;
CTimerMgr::CTimerMgr(uint32 uInterval, uint32 uSlotNum)
: m_uInterval(uInterval),
m_uSlotNum(uSlotNum),
m_uRing(0),
m_uCurSlot(0)
{
for(int i = 0; i < uSlotNum; i++)
{
list<CTimer*>* pTimerList = new list<CTimer*>;
m_vecTimerContainer.push_back(pTimerList);
}
}
CTimerMgr::~CTimerMgr()
{
for(int i = 0; i < m_uSlotNum; i++)
{
list<CTimer*>* pTimerList = m_vecTimerContainer[i];
while(pTimerList->empty())
{
CTimer* pTimer = pTimerList->front();
delete pTimer;
}
delete pTimerList;
}
m_vecTimerContainer.clear();
}
void CTimerMgr::RegisterTimer(CTimer* pTimer, uint32 uInterval)
{
//除了0以外,timer的最小精度为m_uInterval
if(uInterval != 0 && uInterval < m_uInterval)
uInterval = m_uInterval;
uint32 uSlot = m_uCurSlot + uInterval / m_uInterval;
if(uSlot >= m_uSlotNum)
{
pTimer->m_uRing = m_uRing + uSlot / m_uSlotNum;
uSlot = uSlot % m_uSlotNum;
}
else
{
pTimer->m_uRing = m_uRing;
}
list<CTimer*>* pTimerList = m_vecTimerContainer[uSlot];
pTimer->m_pTimerList = pTimerList;
pTimer->m_uInterval = uInterval;
pTimerList->push_back(pTimer);
pTimer->m_itInList = --pTimerList->end();
}
void CTimerMgr::UnRegisterTimer(CTimer* pTimer)
{
if(!pTimer)
return;
list<CTimer*>* pTimerList = pTimer->m_pTimerList;
pTimerList->erase(pTimer->m_itInList);
pTimer->m_pTimerList = NULL;
delete pTimer;
}
void CTimerMgr::OnTimer()
{
list<CTimer*>* pTimerList = m_vecTimerContainer[m_uCurSlot];
list<CTimer*> NextTimerList;
while(!pTimerList->empty())
{
CTimer* pTimer = pTimerList->front();
if(pTimer->m_uRing != m_uRing)
{
NextTimerList.push_back(pTimer);
pTimerList->pop_front();
continue;
}
if(pTimer->m_uInterval == 0)
{
//不停调用,直到删除自己
while(!pTimer->m_pTimerList)
{
pTimer->OnTimer();
}
continue;
}
else
{
pTimer->OnTimer();
//如果timer删除了
if(!pTimer->m_pTimerList)
continue;
uint32 uSlot = pTimer->m_uInterval / m_uInterval;
assert(uSlot > 0);
uSlot += m_uCurSlot;
if(uSlot >= m_uSlotNum)
{
pTimer->m_uRing = m_uRing + uSlot / m_uSlotNum;
uSlot = uSlot % m_uSlotNum;
}
else
{
pTimer->m_uRing = m_uRing;
}
list<CTimer*>* pNewTimerList = m_vecTimerContainer[uSlot];
pTimerList->pop_front();
pNewTimerList->push_back(pTimer);
pTimer->m_pTimerList = pNewTimerList;
pTimer->m_itInList = --pNewTimerList->end();
}
}
pTimerList->swap(NextTimerList);
//移动到下一个slot,如果到了最后,则开始下一轮
++m_uCurSlot;
if(m_uCurSlot == m_uSlotNum)
{
m_uCurSlot = 0;
++m_uRing;
}
}