封装多媒体定时器类和时间核心对象线程类
2013-09-03 14:25
246 查看
背景:虽然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; }
相关文章推荐
- 自己封装的多媒体定时器类和时间核心对象线程类
- 封装对象时候时间处理方式
- 《ASCE1885的源码分析》の跨平台线程对象Thread封装基类
- 在线程中创建GUI核心对象要小心
- java获取本地时间&&jQuery实现ajax&&java封装json对象
- Java 线程封装对象
- 《ASCE1885的源码分析》の跨平台线程对象Thread封装基类
- Linux学习之线程封装一:基于对象的封装
- 【小分享】Date对象封装,时间格式化函数time()
- 优雅设计封装基于Okhttp3的网络框架(三):多线程下载功能核心实现 及 线程池、队列机制、终止线程解析
- Windows 核心编程之6 线程内核对象
- c++类和类的封装,对象线程封装
- 一个自己封装的日期时间操作的用户对象
- Ajax实战总结——用原生JavaScript代码封装自己的Ajax核心对象
- Mybatis核心对象的生命周期与封装
- python使用线程封装的一个简单定时器类实例
- CG学习(2)——CG的基本语法及核心函数的面向对象简单封装
- 【Ajax 2】封装Ajax的核心对象:XMLHttpRequest对象
- C++中面向对象和基于对象的线程封装方法
- 线程核心对象的引用计数