自己封装的多媒体定时器类和时间核心对象线程类

背景:虽然Win95下可视化开发工具如VC、Delphi、C++   Builder等都有专用的定时器控件Timer,而且使用很方便,可以实现一定的定时功能,但最小计时精度仅为55ms,且定时器消息在多任务操作系统中的优先级很低,不能得到及时响应,往往不能满足实时控制环境下的应用。不过Microsoft公司在Win32   API函数库中已经为用户提供了一组用于高精度计时的底层函数,如果用户使用得当,计时精度可到1ms。这个计时精度、对于一般的实时系统控制完全可以满足要求。

在最近的工作中用到计时器的地方比较多,个人尝试了很多中定时器的实现,用于OnTimer定时不能满足要求,于是根据网上的资料封装了两类计时器,供大家参考。因为自己也是初学者,有问题的话请大家给出指导,下面是我封装的两种计时器的类。

多媒体定时器类:

/*
*作者: FreeBird
*描述:多媒体定时器
*完成时间:2013/7/14
*使用方法:重载函数Run
*         1.先调用SetTimerResolution设置分辨率
*         2.调用SetEventType设置事件类型
*         3.调用GetTimerDelay时间周期
*         以上1到3不设置默认:m_nType = TIME_PERIODIC;m_nDelay = 3000;m_nResolution = 1;
*         4.创建定时器CreateTimer
*         5.用完后销毁定时器DestroyTimer
*/

#pragma once
#include <MMSystem.h>
#pragma comment(lib, "Winmm.lib")

class MultimediaTimer
{
public:
	MultimediaTimer(void);
	virtual ~MultimediaTimer(void);

public:
	//创建多媒体定时器
	int CreateTimer();

	//销毁对媒体定时器
	int DestroyTimer();

	//设置分辨率,最小精度1ms,如果设置的超出机器支持的范围,则按照min(机器支持的最小值,1)来设置
	int SetTimerResolution(int nResolution); 

	//获取调用者自己设定的分辨率
	int GetTimerResolution() const;

	//设置以毫秒指定事件的周期
	int SetTimerDelay(int nDelay);

	//获取定时器时间周期
	int GetTimerDelay() const;

	//设置定时器事件类型
	void SetEventType(int nEventType);

	//获取定时器事件类型
	int GetEventType() const;

	//多媒体定时器回调函数
	static void CALLBACK TimerCallBackPro(UINT wTimerID, UINT msg,DWORD dwUser,DWORD dwl,DWORD dw2);

public:
	//子类重载该函数实现不同定时功能
	virtual void Run(); 

private:
	//获得系统支持的计时器装置驱动所支援的最小的解析度值(延时的精度),返回设置的分辨率,返回负数表示失败
	int GetSystemPeriod(int &nPeriodMix, int &nPeriodMax);

private:
	//计时器的精度,默认设置机器支持的最小精度,一般是1ms
	MMRESULT  m_nTimerID;

	//分辨率
	int m_nResolution; 

	//以毫秒指定事件的周期
	int m_nDelay;

	//设置定时器事件类型
	int m_nType;

	//定时器事件类型
	enum eEventType
	{
		RunOnce  = TIME_ONESHOT,      //uDelay毫秒后只产生一次事件
		RunCycle = TIME_PERIODIC      //每隔uDelay毫秒周期性地产生事件。
	};
};


	
#include "StdAfx.h"
#include "MultimediaTimer.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

MultimediaTimer::MultimediaTimer(void)
{
	m_nTimerID = 0;
	m_nType = TIME_PERIODIC;
	m_nDelay = 1000;
	m_nResolution = 1;
}

MultimediaTimer::~MultimediaTimer(void)
{	
}

int MultimediaTimer::CreateTimer()
{
	 if ( timeBeginPeriod(m_nResolution) != TIMERR_NOERROR  )
		return -1;

	 m_nTimerID = timeSetEvent(m_nDelay, m_nResolution, (LPTIMECALLBACK)TimerCallBackPro, (DWORD)this, m_nType);
	 if ( m_nTimerID == 0)
	 {
		 timeEndPeriod(m_nResolution);
		 return -2;		
	 }
	 return 0;
}

int MultimediaTimer::DestroyTimer()
{
	if ( m_nTimerID )
	{
		timeKillEvent(m_nTimerID);
		timeEndPeriod(m_nResolution);
		m_nTimerID = 0;
	}
	return 0;
}

int MultimediaTimer::SetTimerResolution( int nResolution )
{
	int nPeriodMin;  //系统支持的最小值
	int nPeriodMax;  //系统支持的最大值

	//获得机器支持的分辨路范围
	if ( GetSystemPeriod(nPeriodMin, nPeriodMax) != 0 )
		return -1;

	//如果超出机器支持范围按照min(机器支持的最小值,1)来设置
	if ( nResolution < nPeriodMin || nResolution > nPeriodMax )
	{
		m_nResolution = min( max(nPeriodMin, 1), nPeriodMax );
	}
	else 
	{
		m_nResolution = nResolution;
	}

	return 0;
}

int MultimediaTimer::GetTimerResolution() const
{
	return m_nResolution;
}

int MultimediaTimer::GetSystemPeriod(int &nPeriodMix, int &nPeriodMax)
{
	TIMECAPS  tc;  
	//向机器申请一个多媒体定时器       
	if ( timeGetDevCaps(&tc,sizeof(TIMECAPS)) != TIMERR_NOERROR )
		return -1;

	nPeriodMix = tc.wPeriodMin;
	nPeriodMax = tc.wPeriodMax;
	return 0;
}

int MultimediaTimer::SetTimerDelay(int nDelay)
{
	m_nDelay = nDelay;
	return 0;
}

int MultimediaTimer::GetTimerDelay() const
{
	return m_nDelay;
}

void MultimediaTimer::Run()
{

}

void MultimediaTimer::TimerCallBackPro(UINT wTimerID, UINT msg,DWORD dwUser,DWORD dwl,DWORD dw2)
{
	MultimediaTimer *pMulTime = (MultimediaTimer *)dwUser; 
	pMulTime->Run();
}

void MultimediaTimer::SetEventType(int nEventType)
{
	m_nType = nEventType;
}

int MultimediaTimer::GetEventType() const
{
	return m_nType;
}


用线程实现的时间核心对象类:

#include <winbase.h>   //包含了Windows平台专属的一些函数和宏的定义
#include <windows.h>
#include <process.h>   //一般用程序获得进程列表时会用这个文件中的API

class TimerThread 
{
protected:
	HANDLE _TerminateEvent;			//事件句柄
	HANDLE _TimerHandle;			//时间内核对象
	HANDLE _hHandle;				//线程句柄
	unsigned _ThreadID;				//线程ID
	HWND _hNotifyWnd;				// 通知窗口
	LONG _TimerHandleCount;			//时间内核对象调用次数

	LONG _lPeriodTime;				//定时器周期
	SYSTEMTIME _st;					//指定开始执行时间
	int _lSecond;					//指定多少秒后开始执行

	CRITICAL_SECTION _Mutex;		//临界区

protected:	
	virtual void OnInit();		 //初始化,子类需要重载的函数
	virtual void OnTimer()=0;    //定时器函数,子类必须重载的函数	
	virtual void OnExit();       //退出,子类需要重载的函数

	static UINT WINAPI StaticThreadProc(LPVOID lpPara); 
	virtual void Run();         //运行

public:
	TimerThread(int nPriority = THREAD_PRIORITY_NORMAL);  //构造函数中创建事件对象、时间内核对象、初始化临界区并启动线程
	virtual ~TimerThread();

	BOOL SetTimer(LONG lPeriodTime);                //设置定时器,周期执行ms,该函数调用后立即按周期执行
	BOOL SetTimer(SYSTEMTIME st, LONG lPeriodTime); //调用该函数后,在st指定时间到时,按照周期执行
	BOOL SetTimer(int lSecond, LONG lPeriodTime);	//调用该函数后,在指定lSecond秒后开始执行
	void Terminate();					//终止定时器  
	HANDLE GetHandle(); 				//获取线程句柄

	inline void SetWnd(HWND hWnd);      //关联消息的窗口句柄
	LONG GetFinishedCount();            //获取线程被执行次数
};

void TimerThread::SetWnd(HWND hWnd)     //关联消息的窗口句柄
{
	//	assert(::IsWindow(hWnd));
	_hNotifyWnd = hWnd;
}


#endif _TIMER_THREAD_H_ 


 

/*
作者:FreeBird
功能:时间核心对象线程类,该类是抽象类,需要子类实现OnTimer函数,实现定时器的功能
*/

#ifndef _TIMER_THREAD_H_
#define _TIMER_THREAD_H_

#include <objbase.h>   //主持COM的一个头文件


#include "TimerThread.h"
TimerThread::TimerThread(int nPriority)
{
_TimerHandleCount = 0;
_TerminateEvent = CreateEvent(0, TRUE, FALSE, NULL); //创建线程
_TimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);          //创建时间核心对象,自动重置定时器
::InitializeCriticalSection(&_Mutex); //初始化临界区        
unsigned int id;
_hHandle = (HANDLE)_beginthreadex(NULL, 0, StaticThreadProc, this, 0, &id);
_ThreadID = id;
if(_hHandle != NULL)
SetThreadPriority(_hHandle, nPriority); //设置线程优先级
  //else
// MessageBox(NULL, "Create thread fail!", "TimerThread", MB_OK); 
}


TimerThread::~TimerThread()
{
Terminate();   
CloseHandle(_hHandle);  
CloseHandle(_TimerHandle);
CloseHandle(_TerminateEvent); 
::DeleteCriticalSection(&_Mutex);
}


//子类需要重载的函数
void TimerThread::OnInit()
{
}


//OnTimer()函数需要在子类实现
//子类需要重载的函数
void TimerThread::OnExit()
{
}


BOOL TimerThread::SetTimer(LONG lPeriodTime)//ms
{
_lPeriodTime = lPeriodTime;
LARGE_INTEGER liUTC;
memset(&liUTC, 0, sizeof(LARGE_INTEGER));
return SetWaitableTimer(_TimerHandle, &liUTC, _lPeriodTime, NULL, NULL, FALSE)!=0;
}


BOOL TimerThread::SetTimer(SYSTEMTIME st, LONG lPeriodTime)//ms
{
_lPeriodTime = lPeriodTime;
_st = st; //SYSTEMTIME结构,用来设置第1次通知的时间
FILETIME ftLocal, ftUTC;     //FILETIME结构,用来接受STSTEMTIME结构的转换
LARGE_INTEGER liUTC;     //LARGE_INTEGER结构,作为SetWaitableTimer的参数,定时时间
SystemTimeToFileTime(&_st, &ftLocal);           //将SYSTIME结构转换为FILETIME结构
LocalFileTimeToFileTime(&ftLocal, &ftUTC);      //将本地时间转换为标准时间(UTC),SetWaitableTimer函数接受一个标准时间
liUTC.LowPart  = ftUTC.dwLowDateTime;     // 设置LARGE_INTEGER结构,因为该结构数据要作为SetWaitableTimer的参数
liUTC.HighPart = ftUTC.dwHighDateTime;
return SetWaitableTimer(_TimerHandle, &liUTC, _lPeriodTime, NULL, NULL, FALSE) != 0;
}


BOOL TimerThread::SetTimer(int lSecond, LONG lPeriodTime)
{
_lSecond = lSecond;
_lPeriodTime = lPeriodTime;
LARGE_INTEGER li;
const int nTimerUnitsPerSecond = 1000000000 / 100;       //每1s中有多少个100ns
li.QuadPart = -(_lSecond * nTimerUnitsPerSecond );        //负数,表示相对值lSecond秒
return SetWaitableTimer(_TimerHandle, &li, _lPeriodTime, NULL, NULL, FALSE)!=0;
}


void TimerThread::Terminate()
{
SetEvent(_TerminateEvent);
if(WaitForSingleObject(_hHandle, 200) != WAIT_OBJECT_0)
TerminateThread(_hHandle, 0);
}
void TimerThread::Run()
{
HANDLE HandleArray[2];
HandleArray[0] = _TimerHandle;
HandleArray[1] = _TerminateEvent;
for(;;)
{
DWORD ret = WaitForMultipleObjects(2, HandleArray, false, INFINITE); //当其中有一个信号量是往下执行
if(ret == WAIT_OBJECT_0 + 1) //第二个事件发生
break;
if(ret == WAIT_OBJECT_0)     //第一个事件发生
{
try
{
OnTimer();
}
catch (...)
{
}


InterlockedIncrement(&_TimerHandleCount);  //共享变量,互斥锁,时间内核对象被调用次数
}
}
}


HANDLE TimerThread::GetHandle()
{
return _hHandle;
}


LONG TimerThread::GetFinishedCount()
{
return _TimerHandleCount;
}




UINT WINAPI TimerThread::StaticThreadProc(LPVOID lpPara)
{
TimerThread *pObj = (TimerThread*)lpPara;


pObj->OnInit();
pObj->Run();
pObj->OnExit();
return 0;
}


 

 

 



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值