c++ 封装定时器

Thread.h

#pragma once
#include <Windows.h>
#include <iostream>
#include <assert.h>
#include <process.h>

using namespace std;

class CThread
{
public:
	CThread();
	virtual ~CThread();

	HANDLE getHandle() const;
	bool wait();
	bool wait(DWORD timeoutMillsecs);
	void start();
	DWORD terminate(DWORD exitcode=0);

private:

	virtual int run() = 0;
	static unsigned int __stdcall threadFunction(void *threadParam);
	void resetHandle();
private:
	CThread(const CThread&);
	CThread& operator = (const CThread&);
private:
	HANDLE m_handle;
};


Thread.cpp

#include "StdAfx.h"
#include "Thread.h"


CThread::CThread():m_handle(NULL)
{
}

CThread::~CThread()
{
	resetHandle();
}

HANDLE CThread::getHandle() const
{
	return m_handle;
}
void CThread::start()
{
	if (m_handle == NULL)
	{
		unsigned int _threadID = 0;

		m_handle = (HANDLE)::_beginthreadex(0,
			0,
			threadFunction,
			(void*)this,
			0,
			&_threadID
			);
		assert(m_handle!=NULL);
	}
}

bool CThread::wait()
{
	return wait(INFINITE);
}
bool CThread::wait(DWORD timeoutMillsecs)
{
	bool _isOK = false;

	if (NULL == m_handle)
	{
		return true;
	}

	DWORD _result = ::WaitForSingleObject(m_handle,timeoutMillsecs);

	if (_result == WAIT_TIMEOUT)
	{
		_isOK = false;
	}
	if (_result == WAIT_OBJECT_0)
	{
		_isOK = true;
	}
	resetHandle();

	return _isOK;
}

DWORD CThread::terminate(DWORD exitcode)
{
	if (m_handle != NULL && ::TerminateThread(m_handle,exitcode))
	{
		m_handle = NULL;
		return ERROR_SUCCESS;
	}
	else
	{
		return ::GetLastError();
	}
	return 0;
}

unsigned int __stdcall CThread::threadFunction(void *threadParam)
{
	CThread *pThread = (CThread*)threadParam;
	int _ret = pThread->run();

	pThread->resetHandle();
	return _ret;
}
void CThread::resetHandle()
{
	if (m_handle)
	{
		::CloseHandle(m_handle);
		m_handle =NULL;
	}
}

EasyTimer.h

#pragma once
#include <Windows.h>
#include <iostream>
using namespace std;


class CTimeProcess  
{  
public:  
	CTimeProcess(){}  
	~CTimeProcess(){}  
private:  
	void __init(){  
		LARGE_INTEGER nFreq;  
		QueryPerformanceFrequency(&nFreq);  
		m_millsecondsPerTick = 1000.0f / nFreq.QuadPart;  
	}  
public:  
	 __int64 gettime(){  
		static bool _bIsInit = false;  
		if (_bIsInit==false)    {  
			__init();  
			_bIsInit = true;  
		}  

		LARGE_INTEGER nFreq;  
		QueryPerformanceCounter(&nFreq);  
		return ( __int64)(nFreq.QuadPart * m_millsecondsPerTick);  
	}  
public:  
	static CTimeProcess* instance()
	{
		static CTimeProcess tp;  
		return &tp;  
	}
private:  
	double m_millsecondsPerTick;  
};  

#define CURTIME() CTimeProcess::instance() 

//

class CEventHandle
{
public:
	CEventHandle(){}
	virtual ~CEventHandle(){}
	virtual void processEvent() =0;
};

class CEventDemo:public CEventHandle
{
public:
	CEventDemo(){
		
	}
	~CEventDemo(){}
	
	void processEvent()
	{
		cout<<"hello, CEventDemo"<<endl<<endl;
	}
};
class CEventSpecial:public CEventHandle
{
public:
	CEventSpecial(){

	}
	~CEventSpecial(){}

	void processEvent()
	{
		cout<<"hello, CEventSpecial"<<endl<<endl;
	}
};



//
class CEasyTimer
{
public:
	CEasyTimer();
	~CEasyTimer(void);
public:
	bool settimer( int uTimerID, __int64 uEclps, int triggertimes,CEventHandle& pevent);
	bool  killtimer( int uTimerID);
	int getStatus( int uTimerID);
	int getStatus(){return m_bStatus;}
	void setStatus(int nStatus){ m_bStatus = nStatus;}
	 int getID() const { return m_uID ; }
	void processTimer();
	CEasyTimer* create( int uTimerID, __int64 uEclps, int triggertimes);

	 __int64 getlocaltime();
private:

	int m_bStatus;
	 int m_uID;
	 __int64 m_uEclps;

	 __int64 m_begaintime;

	 int m_triggertimes;
	 int m_nTriggled;

	CEventHandle* m_pehandle;
};


enum eTimerStatus
{
	ETS_NONE,
	ETS_RUN,
	ETS_CLOSED,

	ETS_COUNT
};
EasyTimer.cpp

#include "StdAfx.h"
#include "EasyTimer.h"
#include "TimerManager.h"


CEasyTimer::CEasyTimer():m_nTriggled(0)
{
	TIMERMANAGER()->start();
}


CEasyTimer::~CEasyTimer(void)
{
}

bool CEasyTimer::settimer( int uTimerID, __int64 uEclps, int triggertimes,CEventHandle& pevent)
{
	setStatus(ETS_RUN);
	m_pehandle = &pevent;
	bool _bSetResult = TIMERMANAGER()->add((this->create(uTimerID,uEclps,triggertimes)));
	if (_bSetResult)
	{
		m_begaintime = getlocaltime();
		return true;
	}
	return false;
}

CEasyTimer* CEasyTimer::create( int uTimerID, __int64 uEclps, int triggertimes)
{
	m_uID = uTimerID;
	m_uEclps = uEclps;
	m_triggertimes = triggertimes;
	return this;
}
bool CEasyTimer::killtimer( int uTimerID)
{
	return TIMERMANAGER()->del(uTimerID);
}
int CEasyTimer::getStatus( int uTimerID)
{
	return TIMERMANAGER()->getStatus(uTimerID);
}

 __int64 CEasyTimer::getlocaltime()
{
	return CURTIME()->gettime();
}
void CEasyTimer::processTimer()
{
	 __int64 _now=getlocaltime();
	if ( (getStatus() == ETS_RUN) && (m_nTriggled < m_triggertimes) )
	{
		if (_now - m_begaintime >=  m_uEclps*1000)
		{
			m_nTriggled++;//触发了一次
			//处理之
			m_begaintime = getlocaltime();
			m_pehandle->processEvent();
		}
		
	}
	else //触发的次数用完了
	{
		setStatus(ETS_CLOSED);
		//killtimer(m_uID);
	}
	
}

TimerManager.h


#pragma once
#include "Thread.h"
#include "EasyTimer.h"
#include <map>

using namespace std;

class CTimerManager :public CThread
{
	CTimerManager(void);
	~CTimerManager(void);
public:
	static CTimerManager* instance();
	bool add(CEasyTimer* newTimer);
	inline  int getCount() const { return m_nTotalTimerCount ;}
	bool del( int uTimerID);
	int getStatus( int uTimerID);

public:
	int run();
private:
	 int m_nTotalTimerCount;

	typedef map<int,CEasyTimer*> m_mapTimerType;
	m_mapTimerType m_mapTimer;
};

#define  TIMERMANAGER() CTimerManager::instance()


TimerManager.cpp

#include "StdAfx.h"
#include "TimerManager.h"


CTimerManager::CTimerManager(void)
{
}


CTimerManager::~CTimerManager(void)
{
}

CTimerManager* CTimerManager::instance()
{
	static CTimerManager _instance;
	return &_instance;
}
bool CTimerManager::add(CEasyTimer* newTimer)
{
	map<int,CEasyTimer*>::iterator  _iter=m_mapTimer.find(newTimer->getID());

	if ( _iter != m_mapTimer.end())
	{
		return false;
	}
	m_mapTimer.insert(make_pair<int,CEasyTimer*>(newTimer->getID(),newTimer));

	m_nTotalTimerCount++;
	return true;
}

bool CTimerManager::del( int uTimerID)
{
	map<int,CEasyTimer*>::iterator _iter=m_mapTimer.find(uTimerID);

	if ( _iter != m_mapTimer.end() )
	{
		m_mapTimer.erase(_iter);
		m_nTotalTimerCount--;
		return true;
	}
	return false;
}

int CTimerManager::run()
{

	while (true)
	{
		map< int,CEasyTimer*>::iterator  _itBegain = m_mapTimer.begin();
		map< int,CEasyTimer*>::iterator  _itEnd      = m_mapTimer.end();
		map< int,CEasyTimer*>::iterator _it=_itBegain;

		while ( getCount() && (_it != _itEnd ))
		{
			_it->second->processTimer();
			_it++;
		}

		//for check timer status and ease them if the status we get is the time should be kill
		if(getCount())
		{
			map< int,CEasyTimer*>::iterator __it=_itBegain;
			while (__it != _itEnd)
			{
				if (__it->second->getStatus()  ==ETS_CLOSED)
				{
					map< int,CEasyTimer*>::iterator __temp;
					__temp = __it;
					++__it;
					int _id = __temp->second->getID();
					__temp->second->killtimer(_id);

					continue;
				}
				++__it;
			}
		}
		
		
	}
	return 0;
}

int CTimerManager::getStatus( int uTimerID)
{
	map<int,CEasyTimer*>::iterator _iter=m_mapTimer.find(uTimerID);

	if ( _iter != m_mapTimer.end() )
	{
		return _iter->second->getStatus(uTimerID);
	}
	return ETS_NONE;
}


main.cpp

#include "stdafx.h"
#include "EasyTimer.h"


#define MEM_RELEASE(point) \
	{ \
	if(point){ \
		delete point; \
		point = 0 ;\
	} \
	}

int main()
{

	CEventHandle *pEvent = new CEventDemo();
	CEasyTimer *pEasyTime=new CEasyTimer();
	pEasyTime->settimer(100,1,10,*pEvent);//ID:100  每隔一秒触发一次,总共触发10次

	CEventHandle *pEvent2 = new CEventSpecial();
	CEasyTimer *pEasyTime2=new CEasyTimer();
	pEasyTime2->settimer(101,2,10,*pEvent2);

	
	while (true);

	MEM_RELEASE(pEvent);
	MEM_RELEASE(pEasyTime);
	MEM_RELEASE(pEvent2);
	MEM_RELEASE(pEasyTime2);

	return 0;
};


注:这个代码例子有个bug,就是定时器数量级上升时,定时器的线程循环非常耗费,要进行许多无效的遍历,所以造成时间延迟。

可以通过修改定时器的map结构来解决:

1,修改定时器的map为:map<currtime,timestruct>, currtime就是pc当前时间,timestruct是当前遍历的定时器结构,

2,因为map内部使用红黑树生成的,能自动排序key(默认从小到大),所以if判断当前时间是否小于当前遍历到的定时器时间是否满足触发,如果不满足,break。否则将当前需要触发的定时器insert进一个全局队列中,当上一轮循环结束后遍历队列循环进行定时器触发处理。








  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值