Windows下的高精度定时器实现及精确时刻获取

         通讯、VOIP、视频等领域的很多核心技术对时间精度的要求非常高,比如数据采集、时间同步、媒体流平滑控制、拥塞算法等等,很多技术都是以毫秒为单位来进行计算和控制的。但是Windows设计之初并不是以实时系统为目标的,所以Windows系统的时间精度一直不高,实际最小单位是15ms左右,导致的结果就是所有Windows的时间、线程相关的操作都无法以1ms来实现精确控制。

 

        受影响的操作包括Sleep、GetTickCount、_ftime等等。比如你调用Sleep(2),期待2ms之后线程自动唤醒,但是实际结果可能是15ms甚至2x ms的时候才会唤醒,对于简单应用来说影响不大,但是对于精度要求非常高的系统来说,这样的问题就是非常致命的了。

 

代码思路如下:

1、高精度定时器。使用Singleton模式挂起请求Sleep的线程并统一管理,后台使用WindowsMultiMedia SDK的定期回调函数不断检测并回复到时的线程,超时时间与当前时间采用QueryPerformanceCounter/QueryPerformanceFrequency的高精度计时,确保整体功能可靠性。

2、精确时刻获取。由于可以获取到毫秒级别的_ftime与GetTickCount都受到Windows系统时间精度影响,最小单位只有15ms,所以需要借助QueryPerformanceCounter/QueryPerformanceFrequency进行准确计时。代码首先根据_ftime获取起始时刻的精确刻度,然后根据差量计算当前的精确时刻。

 

代码中的Singleton模式可以找到很多实现,因此本文不进行详述

代码(VS2005 c++编译)

高精度定时器

#pragma once

#include <Windows.h>
#include <list>
#include <akumaslab/system/singleton.hpp>

namespace akumaslab{
	namespace time{
		using std::list;

		class PreciseTimerProvider
		{
			struct WaitedHandle{
				HANDLE threadHandle;
				LONGLONG elapsed;//超时时间
			} ;
			typedef list< WaitedHandle > handle_list_type;
			typedef akumaslab::system::Singleton< PreciseTimerProvider > 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 <= 0)return false;
				if (!highResolutionAvailable)return false;
				HANDLE currentThreadHandle = GetCurrentThread();
				HANDLE currentProcessHandle = GetCurrentProcess();
				HANDLE realThreadHandle(0);
				DuplicateHandle(currentProcessHandle, currentThreadHandle, currentProcessHandle, &realThreadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
				WaitedHandle item;
				item.threadHandle = realThreadHandle;
				LARGE_INTEGER now;
				QueryPerformanceCounter(&now);
				now.QuadPart += milliSecond * countPerMilliSecond;
				item.elapsed = now.QuadPart;
				EnterCriticalSection(&critical);
				waitList.push_back(item);
				LeaveCriticalSection(&critical);
				//挂起线程
				SuspendThread(realThreadHandle);
				CloseHandle(realThreadHandle);
				return true;
			}
			//恢复超时线程
			void resumeTimeoutThread()
			{
				if (!highResolutionAvailable)return;
				LARGE_INTEGER now;
				QueryPerformanceCounter(&now);
				EnterCriticalSection(&critical);
				for (handle_list_type::iterator ir = waitList.begin(); ir != waitList.end(); )
				{
					WaitedHandle& waited = *ir;
					if (now.QuadPart >= 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< PreciseTimerProvider > timer_type;
		public:
			static bool wait(int milliSecond)
			{
				//static PreciseTimerProvider timer;
				return timer_type::getRef().suspendCurrentThread(milliSecond);
			}
		};
	}
}

Demo

 

int interval = 1;
	int repeatCount = 50;
	cout << getCurrentTime() << "test begin" << endl;
	unit.reset();
	for (int i = 0; i < repeatCount; i++)
	{
		akumaslab::time::PreciseTimer::wait(interval);
		cout << getCurrentTime() << "/" << getNewTime() << " used " << unit.getPreciseElapsedTime() << " ms" << endl;
		unit.reset();
	}

精确时刻获取

   
#pragma once

#include <sys/timeb.h>
#include <time.h>
#include <Windows.h>
#include <akumaslab/system/singleton.hpp>

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(false), 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< CurrentTimeProvider >::getRef().getCurrentTime(_time);
			}
		};
	}
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值