高效定时器实现方式

一般比较定时器的实现方式有几种

1、升序时间链表,然后tick轮询方式

2、使用时间轮的方式,主要是解决定时器过多,插入时间链表的时间会增长的情况.设定n个槽位,每个槽是一个时间链表

假设有60个槽,每个槽的tick是1s,超时的设定跟槽关系就是 槽位置ts = (cur+(timeout/tick)) % 60, rotation = (timeout/tick )/60

3、使用最小堆的方式(libevent的定时器)libevent是自己写的堆结构,muduo使用的set集合保存时间信息(也是堆结构),libevent借助epoll最后一个参数触发,moduo直接通过循环触发。

实现方式:

#pragma once
#include <functional>
#include <event2/event_compat.h>
#include <event2/event_struct.h>
#include <event2/event.h>
#include <map>

class LibEventTimer
{
public:
	typedef std::function<void(int)> Callback;
	struct TimerPar
	{
		TimerPar()
		{
			pEvent = NULL;
			fIntervalTime = 0;
			bLoop = false;
			nTimerID = -1;
		}
		struct event* pEvent;
		float fIntervalTime;
		Callback callBack;
		bool bLoop;
		int nTimerID;
	};
public:
	LibEventTimer();
	virtual~LibEventTimer();
	int Run_EveryTimer(float fIntervalTime, Callback callBack);
	int Run_AfterTimer(float fIntervalTime, Callback callBack);
	void CancelTimer(int nTimerID);
	void CancelAllTimer();

	static bool Init();
	static void UnInit();

	static bool HeartBeat();

private:
	int CreateTimer(float fIntervalTime, Callback callBack, bool bLoop);
private:

	static struct event_base* base;

	int m_nBaseTimerID;
	typedef std::map<int, TimerPar> TimerParMap;
	TimerParMap m_TimerParsMap;
};
#include "Timer.h"

struct event_base* DK_Timer::base = NULL;

LibEventTimer::LibEventTimer()
{
	m_nBaseTimerID = 0;
	m_TimerParsMap.clear();
}

LibEventTimer::~LibEventTimer()
{
	TimerParMap::iterator it = m_TimerParsMap.begin();
	for (; it != m_TimerParsMap.end();)
	{
		TimerPar& timerPar = it->second;
		if (timerPar.pEvent)
		{
			evtimer_del(timerPar.pEvent);
			delete timerPar.pEvent;
			it = m_TimerParsMap.erase(it);
		}
		else
			++it;
	}
	m_TimerParsMap.clear();
	m_nBaseTimerID = 0;
}

bool LibEventTimer::Init()
{
	base = event_base_new();

	return true;
}

void LibEventTimer::UnInit()
{
	if (base)
	{
		event_base_free(base);
		base = NULL;
	}
}

void OnTimer(int sock, short event, void *arg)
{
	LibEventTimer* pThis = (LibEventTimer*)arg;
	LibEventTimer::TimerPar* pPar = (LibEventTimer::TimerPar*)arg;
	if (pPar->bLoop)
	{
		float fIntervalTime = pPar->fIntervalTime;
		time_t nScend = (time_t)fIntervalTime;
		time_t nUsec = (fIntervalTime - nScend) * 1000000;
		struct timeval tv;
		tv.tv_sec = nScend;
		tv.tv_usec = nUsec;
		evtimer_add(pPar->pEvent, &tv);
	}
	if (pPar->callBack)
		pPar->callBack(pPar->nTimerID);
}


int LibEventTimer::Run_EveryTimer(float fIntervalTime, Callback callBack)
{
	return CreateTimer(fIntervalTime, callBack, true);
}
int LibEventTimer::Run_AfterTimer(float fIntervalTime, Callback callBack)
{
	return CreateTimer(fIntervalTime, callBack, false);
}

int LibEventTimer::CreateTimer(float fIntervalTime, Callback callBack, bool bLoop)
{
	time_t nScend = (time_t)fIntervalTime;
	time_t nUsec = (fIntervalTime - nScend) * 1000000;

	int nNewTimerID = m_nBaseTimerID++;

	TimerPar timerParm;
	timerParm.fIntervalTime = fIntervalTime;
	timerParm.callBack = callBack;
	timerParm.bLoop = bLoop;
	timerParm.nTimerID = nNewTimerID;

	struct timeval tv;
	tv.tv_sec = nScend;
	tv.tv_usec = nUsec;
	struct event* timer_ev = evtimer_new(base, OnTimer, &m_TimerParsMap[nNewTimerID]);
	timerParm.pEvent = timer_ev;
	m_TimerParsMap[nNewTimerID] = timerParm;
	evtimer_add(timer_ev, &tv);
	return nNewTimerID;
}

void LibEventTimer::CancelTimer(int nTimerID)
{
	TimerParMap::iterator it = m_TimerParsMap.find(nTimerID);
	if (it == m_TimerParsMap.end())
	{
		return;
	}
	if (it->second.pEvent)
	{
		evtimer_del(it->second.pEvent);
		delete it->second.pEvent;
		it->second.pEvent = NULL;
	}
	m_TimerParsMap.erase(it);
}
void LibEventTimer::CancelAllTimer()
{
	auto it = m_TimerParsMap.begin();
	while (it != m_TimerParsMap.end())
	{
		int nTimerID = it->first;
		CancelTimer(nTimerID);
		it = m_TimerParsMap.begin();
	}
}


bool LibEventTimer::HeartBeat()
{
	event_base_loop(base, EVLOOP_NONBLOCK);
	return true;
}

 

4、使用set这样的结构保存定时器信息(muduo定时器的实现方式)

这是别人给出的muduo定时器的使用方式,非常简单

https://blog.csdn.net/YoungSusie/article/details/93708907

(3,4 的触发是使用的epoll的超时timeout来触发的)

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值