Windows下的高精度定时器实现及精确时刻获取
2010年06月30日
通讯、VOIP、视频等领域的很多核心技术对时间精度的要求非常高,比如数据采集、时间同步、媒体流平滑控制、拥塞算法等等,很多技术都是以毫秒为单位来进行计算和控制的。但是Windows设计之初并不是以实时系统为目标的,所以Windows系统的时间精度一直不高,实际最小单位是15ms左右,导致的结果就是所有Windows的时间、线程相关的操作都无法以1ms来实现精确控制。
受影响的操作包括Sleep、GetTickCount、_ftime等等。比如你调用Sleep(2),期待2ms之后线程自动唤醒,但是实际结果可能是15ms甚至2x ms的时候才会唤醒,对于简单应用来说影响不大,但是对于精度要求非常高的系统来说,这样的问题就是非常致命的了。
代码思路如下:
1、高精度定时器。使用Singleton模式挂起请求Sleep的线程并统一管理,后台使用Windows MultiMedia SDK的定期回调函数不断检测并回复到时的线程,超时时间与当前时间采用QueryPerformanceCounter/QueryPerformanceFrequency的高精度计时,确保整体功能可靠性。
2、精确时刻获取。由于可以获取到毫秒级别的_ftime与GetTickCount都受到Windows系统时间精度影响,最小单位只有15ms,所以需要借助QueryPerformanceCounter/QueryPerformanceFrequency进行准确计时。代码首先根据_ftime获取起始时刻的精确刻度,然后根据差量计算当前的精确时刻。
代码中的Singleton模式可以找到很多实现,因此本文不进行详述
代码(VS2005 c++编译)
1、高精度定时器 #pragma once #include #include #include namespace akumaslab{ namespace time{ using std::list; class PreciseTimerProvider { struct WaitedHandle{ HANDLE threadHandle; LONGLONG elapsed;//超时时间 } ; typedef list handle_list_type; typedef akumaslab::system::Singleton timer_type; public: PreciseTimerProvider(void):highResolutionAvailable (false), timerID(0) { InitializeCriticalSection(&critical); static LARGE_INTEGER systemFrequency; if(0 != QueryPerformanceFrequency(&systemFrequency)) { timeBeginPeriod(callbackInterval); highResolutionAvailable = true; countPerMilliSecond = systemFrequency.QuadPart/1000; timerID = timeSetEvent(callbackInterval, 0, &PreciseTimerProvider::TimerFunc, NULL, TIME_PERIODIC); } } //挂起当前线程 //@milliSecond:超时时间,单位:毫秒 bool suspendCurrentThread(int milliSecond) { if(milliSecond = waited.elapsed) { ResumeThread(waited.threadHandle); ir = waitList.erase(ir); continue; } ir++; } LeaveCriticalSection(&critical); } ~PreciseTimerProvider(){ if (0 != timerID) { timeKillEvent(timerID); timerID = 0; timeEndPeriod(callbackInterval); } DeleteCriticalSection(&critical); } private: static void CALLBACK TimerFunc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { static bool initialed = false; if (!initialed) { if (initialWorkThread()) { initialed = true; } else{ return; } } timer_type::getRef().resumeTimeoutThread(); } //调整定时器工作线程优先级 static bool initialWorkThread() { HANDLE realProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, _getpid()); if (NULL == realProcessHandle) { return false; } if (0 == SetPriorityClass(realProcessHandle, REALTIME_PRIORITY_CLASS)) { CloseHandle(realProcessHandle); return false; } HANDLE currentThreadHandle = GetCurrentThread(); HANDLE currentProcessHandle = GetCurrentProcess(); HANDLE realThreadHandle(0); DuplicateHandle(currentProcessHandle, currentThreadHandle, currentProcessHandle, &realThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); SetThreadPriority(realThreadHandle, THREAD_PRIORITY_TIME_CRITICAL); //必须关闭复制句柄 CloseHandle(realThreadHandle); CloseHandle(realProcessHandle); return true; } private: const static int callbackInterval = 1; CRITICAL_SECTION critical; MMRESULT timerID; LONGLONG countPerMilliSecond; bool highResolutionAvailable; handle_list_type waitList; }; class PreciseTimer { typedef akumaslab::system::Singleton timer_type; public: static bool wait(int milliSecond) { //static PreciseTimerProvider timer; return timer_type::getRef().suspendCurrentThread(milliSec ond); } }; } } DEMO int interval = 1; int repeatCount = 50; cout #include #include #include namespace akumaslab{ namespace time{ struct HighResolutionTime { int year; int month; int day; int hour; int min; int second; int millisecond; }; class CurrentTimeProvider { public: CurrentTimeProvider():highResolutionAvailable(fals e), countPerMilliSecond(0), beginCount(0) { static LARGE_INTEGER systemFrequency; if(0 != QueryPerformanceFrequency(&systemFrequency)) { highResolutionAvailable = true; countPerMilliSecond = systemFrequency.QuadPart/1000; _timeb tb; _ftime_s(&tb); unsigned short currentMilli = tb.millitm; LARGE_INTEGER now; QueryPerformanceCounter(&now); beginCount = now.QuadPart - (currentMilli*countPerMilliSecond); } }; bool getCurrentTime(HighResolutionTime& _time) { time_t tt; ::time(&tt); tm now; localtime_s(&now, &tt); _time.year = now.tm_year + 1900; _time.month = now.tm_mon + 1; _time.day = now.tm_mday + 1; _time.hour = now.tm_hour; _time.min = now.tm_min; _time.second = now.tm_sec; if (!highResolutionAvailable) { _time.millisecond = 0; } else{ LARGE_INTEGER qfc; QueryPerformanceCounter(&qfc); _time.millisecond = (int)((qfc.QuadPart - beginCount)/countPerMilliSecond)%1000; } return true; } private: bool highResolutionAvailable; LONGLONG countPerMilliSecond; LONGLONG beginCount; }; class CurrentTime { public: static bool get(HighResolutionTime& _time) { return akumaslab::system::Singleton::getRef().getCurrentTime(_time); } }; } } DEMO: HighResolutionTime time; CurrentTime::get(time); const int size = 20; char buf[size] = {0}; _snprintf_s(buf, size, size, "%02d:%02d %02d:%02d:%02d.%03d ", time.month, time.day, time.hour, time.min, time.second, time.millisecond); 测试结果如下,下图是高精度计时器按1ms进行Sleep的结果,左侧为使用_ftime计时,右侧为使用精确时刻计时,总体来说,虽然无法达到100%可靠,但是相对原来的15ms已经有较大提升,期望Windows能够尽快提供真正的高精度时间管理技术
发表评论
-
Windows Installer的简单应用
2012-01-20 00:29 749Windows Installer的简单应 ... -
在android 2.3 AVD 模拟器上安装 google market 安卓市场
2012-01-20 00:29 486在android 2.3 AVD 模拟器上安装 google ... -
在android 2.3 AVD 模拟器上安装 google market 安卓市场
2012-01-20 00:29 739在android 2.3 AVD 模拟器上安装 google ... -
在windows下编译生成支持gdb stub的bochs以方便我的操作系统uwos调试
2012-01-20 00:29 1215在windows下编译生成支持gdb stub的bochs以方 ... -
三年级如何写作文
2012-01-19 01:26 532三年级如何写作文 2011年10月27日 三年级如何写 ... -
小学生评语大全
2012-01-19 01:26 715小学生评语大全 2011年07月14日 你是一位可爱的小 ... -
小学生期末评语经典大全
2012-01-19 01:26 838小学生期末评语经典大全 2011年12月15日 1.你是 ... -
超级爆笑小学生作文大全,这孩子太搞了
2012-01-19 01:26 565超级爆笑小学生作文大全,这孩子太搞了 2011年11月03日 ... -
VC编译器配置及编译选项
2012-01-19 01:26 594VC编译器配置及编译选 ... -
电脑蓝屏
2012-01-17 00:42 572电脑蓝屏 2011年08月10日 电脑蓝屏7e 8e ... -
DOS初级教程
2012-01-17 00:42 765DOS初级教程 2011年09月04日 D ... -
7月16号 键盘按键失灵? 蓝屏的终极处理?
2012-01-17 00:42 6537月16号 键盘按键失灵? 蓝屏的终极处理? 2011年07 ... -
夜魅-----【索爱刷机必备。刷机控】
2012-01-17 00:42 604夜魅-----【索爱刷机必备。刷机控】 2011年12月31 ... -
小学高段学生主体参与作文批改的策略
2012-01-15 15:04 903小学高段学生主体参与作文批改的策略 2011年04月17日 ... -
何培养小学生作文批改能力
2012-01-15 15:04 674何培养小学生作文批改能力 2010年10月14日 文评改 ... -
作文批改评语
2012-01-15 15:04 536作文批改评语 2010年05 ... -
作文批改评语范例
2012-01-15 15:04 621作文批改评语范例 2011 ...
相关推荐
Windows平台高精度定时器封装类,最高精度可达1ms。
Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现
qt及windows提供的定时器在ms级延时时是无法精确到ms的,因此写了一个获取cpu的高精度定时器,仅限在pc机上使用,因为会占用cpu资源不建议在单片机及arm上使用
windows自带的定时器精度一般在10ms量级,精确度不足,在部分需要高精度定时的应用场合中,需要一种更高精度的定时器。 该高精度定时器能提供约1ms的定时精度,在轻负荷条件下的定时精度较稳定。 关键的是,该定时器...
嵌入式Linux下高精度定时器的实现,范异君,,嵌入式Linux开发过程中经常遇到需要设定大量定时器的情况,随着嵌入式技术的发展,嵌入式Linux应用场合也越来越广,在定时的精度以��
Visual C++实现微秒级精度定时器。
用VisualC_6_0实现高精度定时器用VisualC_6_0实现高精度定时器用VisualC_6_0实现高精度定时器用VisualC_6_0实现高精度定时器用VisualC_6_0实现高精度定时器
通过使用硬件支持高精度计时器以及CPU主频实现高精度定时器,计时器
如何制作高精度的WINDOWS定时器
c#高精度定时器程序. 项目用C#2010完成,Win7下测试,定时器的精度很好。 程序的主要实现方法:在线程中用WIN32的API的 QueryPerformanceCounter、QueryPerformanceFrequency来不断的查询时间。
比Timer定时器的精度更高的定时器,做实时控制经常使用的控制器
vs2019 MFC 多媒体定时器 ms级定时器
delphi 下的高精度定时器组件,支持分辨率最小 1ms。可用于精确定时和计数。带测试例子。
高精度定时器,但暂停、复位功能,使用双缓冲,一点不闪烁。蓝底白字。
精度可以准确到1ms 误差不超2ms 相比系统的那个不稳定的定时器有很大改善 修正了Win10下报错问题
windows 高精度多媒体定时器,支持毫秒精确定时
用VB编写的高精度定时器,源代码都是人家的,自己用VB将其编出来实现了定时功能。
论文《Linux内核中一种高精度定时器的设计与实现》