使用时间轮实现的定时器

时间轮是一种很有趣的设计,可以用来实现一个简单高效的定时器,很多游戏系统都使用它。

附代码:


timer.h

#ifndef _TIMER_H_
#define _TIMER_H_

#include "typedef.h"
#include "mutex.h"
#include "event.h"

namespace Test
{
	typedef struct {
		C8  name[ STW_NAME_LENGTH ];
		U32  magicTag;  
		U32  wheelSize;
		U32  spokeIndex; 
		U32  ticks; 
		U32  granularity; 

		U32  hiwaterMark;
		U32  active;
		U32  cancelled;
		U32  expired;
		U32  starts;

		typedef TNodeList SPOKE;
		SPOKE spokes[WHEEL_SIZE];
	} STW;

	struct CEvent;

	class CTimer
	{
	public:
		CTimer(U32 wheel_size, U32 granularity, const char* name);
		~CTimer(void);

		bool TimerRunning(CEvent* tmr);
		void TimerPrepare(CEvent* tmr);
		void TimerStats(void);
		RC_STW TimerStart(CEvent* tmr,U32 delay,U32 perioddelay);
		RC_STW TimerStop(CEvent* tmr);
		void TimerTick(void);
		void Enqueue(CEvent* tmr, U32 delay);

	private:
		CTimer(void);
		STW m_stw;
		CMutex m_mutex;
	};
}

#endif //_TIMER_H_


timer.cpp

#include 
#include 
#include 

#include "timer.h"

namespace Test
{
	CTimer::CTimer(U32 wheelSize, U32 granularity, const char* name)
	{
		memset(m_stw.name, 0, sizeof(m_stw.name));

		if( wheelSizeSTW_MAX_WHEEL_SIZE )
		{
			return;
		}

		if( granularitySTW_MAX_GRANULARITY )
		{
			return;
		}

		strcpy(m_stw.name, name);
		m_stw.magicTag = MAGIC_TAG;
		m_stw.ticks = 0;
		m_stw.spokeIndex = 0;
		m_stw.granularity = granularity;
		m_stw.wheelSize  = wheelSize;

		m_stw.hiwaterMark  = 0;
		m_stw.active = 0;
		m_stw.cancelled=0;
		m_stw.expired=0;
		m_stw.starts=0;
	}

	CTimer::~CTimer(void)
	{
		if( m_stw.magicTag!=MAGIC_TAG )
		{
			return;
		}

		m_stw.magicTag = 0;
	}

	void CTimer::Enqueue(CEvent* tmr, U32 delay)
	{
		U32 cursor = 0;
		U32 ticks = 0;
		U32 td = 0;
		
		LOCK_INTERRUPTS();

		if( delayrotCount = (ticks / m_stw.wheelSize);
		cursor = ((m_stw.spokeIndex + td) % m_stw.wheelSize);
		m_stw.spokes[cursor].PushNode(tmr);

		UNLOCK_INTERRUPTS();

		return;
	}

	void CTimer::TimerStats(void)
	{
		if( m_stw.magicTag!=MAGIC_TAG )
		{
			return;
		}

		printf("\n%s \n", m_stw.name);
		printf("       Granularity=%u\n", m_stw.granularity);
		printf("        Wheel Size=%u\n", WHEEL_SIZE);
		printf("        Tick Count=%u\n", m_stw.ticks);
		printf("       Spoke Index=%u\n", m_stw.spokeIndex);

		printf("     Active timers=%u\n", m_stw.active);
		printf("    Expired timers=%u\n", m_stw.expired);
		printf("      Hiwater mark=%u\n", m_stw.hiwaterMark);
		printf("    Started timers=%u\n", m_stw.starts);
		printf("  Cancelled timers=%u\n", m_stw.cancelled);
		return;
	}

	bool CTimer::TimerRunning(CEvent* tmr)
	{
		if( tmr==NULL )
		{
			return false;
		}

		if( tmr->Next()!=NULL )
		{
			return true;
		}

		return false;
	}

	void CTimer::TimerPrepare(CEvent* tmr)
	{
		if( tmr )
		{
			tmr->m_pNext = NULL;
			tmr->m_pPrev = NULL;
		}
	}

	RC_STW CTimer::TimerStart(CEvent* tmr, U32 delay, U32 perioddelay)
	{
		if( tmr==NULL )
		{
			return (RC_STW_NULL_TMR);
		}

		if( m_stw.magicTag!=MAGIC_TAG )
		{
		   return (RC_STW_INVALID_WHEEL);
		}

		LOCK_INTERRUPTS();

		if( tmr->Next() )
		{
			tmr->RemoveFromList();
			m_stw.active--;
		}

		UNLOCK_INTERRUPTS();

		tmr->delay      	= delay;
		tmr->priDelay 	= perioddelay;

		Enqueue(tmr, delay);


		m_stw.starts++;
		m_stw.active++;
		if( m_stw.active>m_stw.hiwaterMark )
		{
			m_stw.hiwaterMark = m_stw.active;
		}

		return (RC_STW_OK);
	}

	RC_STW CTimer::TimerStop(CEvent* tmr)
	{
		if( tmr==NULL )
		{
			return (RC_STW_NULL_TMR);
		}

		if( m_stw.magicTag!=MAGIC_TAG )
		{
			return (RC_STW_INVALID_WHEEL);
		}

		LOCK_INTERRUPTS();

		tmr->RemoveFromList();
		TimerPrepare(tmr);
		m_stw.active--;
		m_stw.cancelled++;

		UNLOCK_INTERRUPTS();

		return (RC_STW_OK);
	}

	void CTimer::TimerTick(void)
	{
		if( m_stw.magicTag!=MAGIC_TAG )
		{
			return;
		}

		m_stw.ticks++;

		m_stw.spokeIndex = (m_stw.spokeIndex+1) % m_stw.wheelSize;

		CEvent* pcur = (CEvent*)m_stw.spokes[m_stw.spokeIndex].Head();
		CEvent* pnext = NULL;
		while( pcur )
		{
			if( pcur->rotCount!=0 )
			{
				pcur->rotCount--;
			}
			else
			{
				LOCK_INTERRUPTS();
				pnext = (CEvent*)pcur->Next();
				pcur->RemoveFromList();

				m_stw.active--;
				m_stw.expired++;

				UNLOCK_INTERRUPTS();

				pcur->OnTimerOut();

			}
			
			pcur = pnext;
		}
		return;
	}
}


你可能感兴趣的:(使用时间轮实现的定时器)