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能够尽快提供真正的高精度时间管理技术
发表评论
-
VC6应用WMI获取系统信息
2012-01-20 09:31 1029VC6应用WMI获取系统信息 2011年05月02日 花 ... -
Windows Installer的简单应用
2012-01-20 09:31 694Windows Installer的简单应 ... -
在android 2.3 AVD 模拟器上安装 google market 安卓市场
2012-01-20 09:31 576在android 2.3 AVD 模拟器上安装 google ... -
在android 2.3 AVD 模拟器上安装 google market 安卓市场
2012-01-20 09:31 576在android 2.3 AVD 模拟器上安装 google ... -
载沣:“瑜伽王爷”的柔软身段(二)
2012-01-19 14:33 514载沣:“瑜伽王爷”的柔软身段(二) 2012年01月09日 ... -
论外格用舍
2012-01-19 14:33 586论外格用舍 2012年01月13日 二十二、论外格用舍 ... -
中国人的用餐礼仪~~~有空大家看看,蛮受用的哦
2012-01-19 14:33 598中国人的用餐礼仪~~~有空大家看看,蛮受用的哦 2009年0 ... -
一代天骄成吉思汗的秘葬
2012-01-19 14:33 621一代天骄成吉思汗的秘 ... -
《论语》解读之3-19《使下以礼事上以忠》
2012-01-19 14:33 623《论语》解读之3-19《使下以礼事上以忠》 2011年12月 ... -
Flex动态创建类对象
2012-01-17 04:21 653Flex动态创建类对象 2010年08月07日 自Act ... -
107条Javascript的常用语句
2012-01-17 04:21 469107条Javascript的常用语句 2010年12月31 ... -
学习JavaScript---对象
2012-01-17 04:21 514学习JavaScript---对象 2010年10月01日 ... -
JavaScript内置对象
2012-01-17 04:20 463JavaScript内置对象 2010年11月01日 ... -
JS学习---ECMAScript对象
2012-01-17 04:20 587JS学习---ECMAScript对象 2010年11月25 ... -
女性最为吸引人的品质
2012-01-16 03:10 438女性最为吸引人的品质 2009年10月11日 ... -
现代女性怎样说话才可爱
2012-01-16 03:10 715现代女性怎样说话才可 ... -
流利口语脱口而出第九课
2012-01-16 03:10 558流利口语脱口而出第九课 2009年10月13日 第九课 ... -
女性恋爱时在意的11件事情
2012-01-16 03:10 529女性恋爱时在意的11件事情 2009年07月31日 如果 ... -
女性最为吸引人的品质
2012-01-16 03:10 430女性最为吸引人的品质 ...
相关推荐
总结来说,"Windows高精度定时器(VC++实现)"是利用Windows消息机制和高级计时API实现的,主要目标是提供毫秒级精度的定时服务,便于开发者在需要精确控制时间的场景下进行编程。`MessageTimer`类可能是这一实现的...
在常规的QT和Windows系统中,内置的定时器在处理毫秒级别的延时时可能存在精度不足的问题,这可能会影响到一些对时间精确度要求极高的应用,比如游戏引擎、实时数据处理或精密算法的实现。 QT库提供了QTimer类作为...
Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现Windows2000下高精度定时器设计与实现
在 Delphi 开发环境中,创建高精度定时器是实现精确计时和事件调度的关键。"高精度定时器最高精度 1ms" 提供了一个能够达到毫秒级精度的定时器组件,这对于需要实时响应或者时间敏感的应用程序尤其重要。毫秒级...
总的来说,“C#高精度定时器”是一种为了提高Windows系统定时精度的解决方案,通过封装底层API,使得开发者可以在Win7系统上实现接近1毫秒的定时精度,满足对时间敏感的应用需求。使用时,根据提供的使用说明和示例...
windows自带的定时器精度一般在10ms量级,精确度不足,在部分需要高精度定时的应用场合中,需要一种更高精度的定时器。 该高精度定时器能提供约1ms的定时精度,在轻负荷条件下的定时精度较稳定。 关键的是,该定时器...
"VC 实现微秒级精度定时器" 本文将讨论如何使用 Visual C++ 实现微秒级精度定时器。该定时器可以应用于工业生产控制系统、数据采集系统等领域,对控制性能和数据采集速度有着很高的要求。 为什么需要微秒级精度...
2. **POSIX gettimeofday**:在Linux系统中,可以使用gettimeofday函数获取高分辨率的时间戳,其精度通常为微秒级。 3. **std::chrono库**:C++11引入的std::chrono库提供了高精度时间点和持续时间的处理,可以方便...
c#高精度毫秒定时器,实现windows高精度定时器功能,参考 C#上位机1ms级高精度定时任务讲解 ...高精度定时器的使用以及实现 ...
总之,高精度定时器和计时器是通过硬件支持的定时器和CPU主频的结合来实现的,它们在需要精确时间控制的场景中起着至关重要的作用。理解其工作原理并正确使用这些技术,可以帮助开发者编写出更加高效和精确的程序。
高精度定时器的实现利用了现代硬件提供的更精确的时钟源,如HPET(High Precision Event Timer)或TSC(Time Stamp Counter)。这些硬件定时器可以提供比系统心跳更精细的时间基准,从而实现纳秒级别的计时精度。 ...
总之,高精度多媒体定时器是Windows平台下解决低延迟、高精度计时问题的有效工具。它的使用使得开发者能够在实时控制系统、多媒体应用和其他对时间精度要求高的场景中实现更精确的控制,提升了软件的性能和用户体验...
4. **高精度API**:操作系统提供了如Windows的QueryPerformanceCounter或Linux的clock_gettime等高精度计时函数,可以直接获取硬件时钟的值,从而实现精确计时。 在多线程环境中,高精度定时器的作用尤为显著。例如...
用VisualC_6_0实现高精度定时器用VisualC_6_0实现高精度定时器用VisualC_6_0实现高精度定时器用VisualC_6_0实现高精度定时器用VisualC_6_0实现高精度定时器
在"高精度定时器"这个压缩包文件中,可能包含了一个示例项目或者源代码,演示如何在VC++或EVC环境下使用timeSetEvent函数创建高精度定时器。通过学习和理解这些代码,开发者可以更好地掌握如何在Windows应用中实现...
本项目基于VS2019,专注于实现高精度的定时器功能,特别是多媒体定时器,它允许开发者实现毫秒级别的精确计时。下面我们将深入探讨MFC中的定时器机制,以及如何在VS2019中实现这些功能。 首先,MFC中的定时器分为两...
1. **计时器API**:程序可能使用了特定的操作系统提供的计时器API,例如在Windows系统中,可以使用QueryPerformanceCounter()函数获取高精度时间,而在Linux或Unix系统中,可以利用gettimeofday()或clock_gettime()...