使用时间轮实现的定时器

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

附代码:


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<CEvent> 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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "timer.h"

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

		if( wheelSize<STW_MIN_WHEEL_SIZE
			|| wheelSize>STW_MAX_WHEEL_SIZE )
		{
			return;
		}

		if( granularity<STW_MIN_GRANULARITY
			|| granularity>STW_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( delay<m_stw.granularity )
		{
			ticks = 1;
		}
		else
		{
			ticks = (delay / m_stw.granularity);
		}

		td = (ticks % m_stw.wheelSize);
		tmr->rotCount = (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;
	}
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty是一个基于Java的高性能网络通信框架,它提供了一些方便的功能,包括时间定时任务。时间是一种用于执行定时任务的数据结构,它可以提高定时任务的触发精度和执行效率。 在Netty中,时间定时任务是通过`HashedWheelTimer`类实现的。下面是一个简单的示例代码,演示如何在Netty中使用时间定时任务: ```java import io.netty.util.HashedWheelTimer; import io.netty.util.Timeout; import io.netty.util.TimerTask; public class TimeWheelExample { public static void main(String[] args) { // 创建时间定时器 HashedWheelTimer timer = new HashedWheelTimer(); // 创建定时任务 TimerTask task = new TimerTask() { @Override public void run(Timeout timeout) throws Exception { System.out.println("定时任务执行"); } }; // 将定时任务提交给时间定时器,延迟2秒后执行 timer.newTimeout(task, 2, TimeUnit.SECONDS); } } ``` 在上面的示例中,我们首先创建了一个`HashedWheelTimer`实例,然后创建了一个`TimerTask`对象,定义了要执行的定时任务。最后,我们使用`timer.newTimeout()`方法将定时任务提交给时间定时器,并指定了延迟时间为2秒。 当时间定时器触发定时任务时,会调用`run()`方法执行任务。在这个例子中,定时任务执行时,会简单地打印一条消息。 需要注意的是,时间定时任务仅限于在Netty中使用,如果你想在其他环境或框架中使用时间定时任务,可能需要使用其他的定时任务实现方式

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值