高精度计时器QueryPerformanceCounter正确的打开方式(windows环境下)
来源:互联网 发布:windows phone 流畅 编辑:程序博客网 时间:2024/05/14 07:39
引言
游戏程序中有很多需要用到时间的地方,往往会通过windows API来获取时间。先前写过一篇文章是关于时间同步的:网络游戏中的(低精度)时间同步,当需求更高精度的时间同步时,就需要QueryPerformanceCounter这样的API,而QueryPerformanceCounter的使用有一些隐含的陷阱需要注意。
关于QueryPerformanceCounter
官方解释:https://msdn.microsoft.com/zh-cn/ms644904,用于高精度计时器时间读取,重点是执行成功返回非0值,精度是<1us的。
多核CPU采用QueryPerformanceCounter的问题
程序中通常使用时间差定时地调用某种接口的情况,而时间差的使用有一个隐含因素,即时间是顺序累加的,当然我们通常的时间当然是累加的,不会出现停滞甚至倒转,而QueryPerformanceCounter的运行情况是依赖于CPU的,当CPU是多核时,在某一线程内调用QueryPerformanceCounter,线程会切换于不同的核心之间,这时候QueryPerformanceCounter返回值是不确定的,或者说这时候的计时器并不能保证是顺序累加的,相应地,当使用时间差时会出现负数或者0的情况,这显然不符合开发者的预期。
如何在多核CPU的环境下使用QueryPerformanceCounter
目前多核的CPU已经飞入寻常百姓人家,因而作为开发人员,不得不面对在多核CPU的机器上使用QueryPerformanceCounter的情况。当我们需要在某一进程中获取时间,需要将该线程绑定在某一固定的核心上,这样获取的高精度计时器才是可靠的。通过SetThreadAffinityMask可以实现这一目的。举个栗子:
参考资料:
http://bbs.csdn.net/topics/310177138
https://msdn.microsoft.com/en-us/library/ee417693%28v=vs.85%29.aspx
http://blog.csdn.net/hunter8777/article/details/6204719
HANDLE thread = GetCurrentThread();// Set affinity to the first coreDWORD_PTR oldMask = SetThreadAffinityMask(thread, GTimerMask );// Query the timerQueryPerformanceCounter(&mStartTime);mStartTick = GetTickCount();// Reset affinitySetThreadAffinityMask(thread, oldMask);使用前,需要重置GTimerMask:
void appResetTimerMask(){// Get the current process core maskULONG_PTR proMask;ULONG_PTR sysMask;GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);// If procMask is 0, consider there is only one core available// (using 0 as procMask will cause an infinite loop below)if (procMask == 0) procMask = 1;// Find the lowest core that this process uses if (GTimerMask == 0) { GTimeMask = 1; while ((GTimerMask & procMask) == 0) { GTimerMask <<= 1; } }}完整的使用方法:
inline DOUBLE appSeconds(){LARGE_INTEGER Cycles;HANDLE thread = NULL;ULONG_PTR oldMask = 0;if (GEnableTimerAffinityMask) //GEnableTimerAffinityMask为TRUE时需要将线程绑定到固定核心{thread = GetCurrentThread();if (GTimerMask == 0) //GTimerMask默认值为0{appResetTimerMask();}oldMask = SetThreadAffinityMask(thread, GTimerMask);}QueryPerformanceCounter(&Cycles);if (GEnableTimerAffinityMask){SetThreadAffinityMask(thread, oldMask);}return Cycles.QuadPart * GSecondsPerCycle + 16777216.0;}
参考资料:
http://bbs.csdn.net/topics/310177138
https://msdn.microsoft.com/en-us/library/ee417693%28v=vs.85%29.aspx
http://blog.csdn.net/hunter8777/article/details/6204719
1 0
- 高精度计时器QueryPerformanceCounter正确的打开方式(windows环境下)
- 高精度计时器---QueryPerformanceFrequency()与QueryPerformanceCounter()的使用
- QueryPerformanceFrequency Window下的高精度计时器
- QueryPerformanceFrequency Window下的高精度计时器
- Windows环境打开文件的方式总结
- SimpleSwitch的(正确?)打开方式
- Windows/Linux高精度计时器(C++)
- Windows/Linux高精度计时器(C++)
- 【C++】高精度代码运行时间( QueryPerformanceCounter )
- windows下的时间计时器
- Windows下使用Python配制环境以及打开方式
- 过滤器的正确打开方式
- Emacs的正确打开方式...
- ScaleDrawable的正确打开方式
- Baidu的正确打开方式
- 算法的正确打开方式
- Activity的正确打开方式
- Activity的正确打开方式
- 【LeetCode】021.Merge Two Sorted Lists
- 第二章第二题
- Matlab 提取矩阵 某一行 或者 某一列 的方法
- 题6
- 第二章第六题
- 高精度计时器QueryPerformanceCounter正确的打开方式(windows环境下)
- MySQL、SqlServer、Oracle三大主流数据库分页查询
- getline()函数总结
- 杂谈:如何调试CUDA代码
- Opencv2:1.5 载入、显示及保存图像
- [Python]网络爬虫(一):抓取网页的含义和URL基本构成
- 今天是2015.3.26 我开始我写博客的日子了
- RaspberryPi上FreeSWITCH自启动
- Memcache 分布式高可用集群介绍