timeGetTime似乎非常适合查询系统时间。但是,它的返回值仅为32位,所以每约49天就会回绕一次。
在调用代码时检测翻转并不太难,但它增加了一些复杂性,并且(更糟)需要保持状态。
是否有一些替代timeGetTime没有这种环绕问题(可能通过返回64位值),并且具有大致相同的精度和成本?
答案 0 :(得分:5)
什么平台?
如果您在Vista或更高版本上运行,可以使用GetTickCount64(),或者从GetTickCount64()
和计时器合成您自己的GetTickCount()
...
我处理GetTickCount()
中的翻转问题,并在我的博客上关于测试非平凡代码的平台上合成GetTickCount64()
:http://www.lenholgate.com/blog/2008/04/practical-testing-17---a-whole-new-approach.html
答案 1 :(得分:5)
除非您需要为超过49天的活动计时,您可以安全地忽略环绕。只需总是从当前timeGetTime()中减去前一个timeGetTime(),你将总是获得准确的增量测量时间,即使是在环绕 - ,只要你是计时事件总持续时间少于49天。这一切都起作用,因为计算机内部的无符号模块化数学运算。
// this code ALWAYS works, even with wrap-around!
DWORD dwStart = timeGetTime();
// provided the event timed here has a duration of less than 49 days
DWORD dwDuration = timeGetTime()-dwStart;
提示:查看TimeBeginPeriod(1L)以提高timeGetTime()的准确性。
但是......如果你想要一个64位版本的timeGetTime,这里是:
__int64 timeGetTime64() {
static __int64 time64=0;
// warning: if multiple threads call this function, protect with a critical section!
return (time64 += (timeGetTime()-(DWORD)time64));
}
请注意,如果此功能每49天至少调用一次,则此功能将无法正确检测环绕。
答案 2 :(得分:2)
不,跟踪翻转需要状态。它可以像在每次回调时递增自己的64位计数器一样简单。
想要将时间段跟踪到低至1毫秒的分辨率长达49天是非常不寻常的。你不得不担心在这么长的时间后,准确性仍然存在。下一步是使用时钟,GetTickCount(64),GetSystemTimeAsFileTime的分辨率为15.625毫秒,并且使用时间服务器保持准确。
答案 3 :(得分:1)
看看GetSystemTimeAsFileTime()。它填充FILETIME
结构,其中包含“64位值,表示自1601年1月1日(UTC)以来100纳秒间隔的数量”
答案 4 :(得分:1)
你是如何尝试使用它的?在检查我知道将在49天内的持续时间时,我经常使用Win32等效项。例如,以下代码将始终有效。
DWORD start = timeGetTime();
DoSomthingThatTakesLessThen49Days();
DWORD duration = timeGetTime() - start;
即使在调用timeGetTime
DoSomthingThatTakesLessThen49Days
时duration
翻身仍然是正确的。
请注意,以下代码可能会在翻转时失败。
DWORD start = timeGetTime();
DoSomthingThatTakesLessThen49Days();
if (now + 5000 < timeGetTime())
{
}
但可以很容易地重写如下工作
DWORD start = timeGetTime();
DoSomthingThatTakesLessThen49Days();
if (timeGetTime() - start < 5000)
{
}
答案 5 :(得分:1)
假设您可以保证此功能每49天至少调用一次,这样的话会起作用:
// Returns current time in milliseconds
uint64_t timeGetTime64()
{
static uint32_t _prevVal = 0;
static uint64_t _wrapOffset = 0;
uint32_t newVal = (uint32_t) timeGetTime();
if (newVal < _prevVal) _wrapOffset += (((uint64_t)1)<<32);
_prevVal = newVal;
return _wrapOffset+newVal;
}
请注意,由于使用了静态变量,此函数不是多线程安全的,因此如果您计划从多个线程调用它,则应通过关键部分或互斥或类似函数对其进行序列化。
答案 6 :(得分:1)
我不确定这是否完全符合您的需求,但
std::chrono::system_clock
可能与您正在寻找的内容相符。
答案 7 :(得分:0)
你可以使用RDTSC内在的。要以毫秒为单位获得时间,您可以获得变换系数:
double get_rdtsc_coeff() {
static double coeff = 0.0;
if ( coeff < 1.0 ) { // count it only once
unsigned __int64 t00 = __rdtsc();
Sleep(1000);
unsigned __int64 t01 = __rdtsc();
coeff = (t01-t00)/1000.0;
}
return coeff; // transformation coefficient
}
现在你可以得到上一次重置后的毫秒数:
__int64 get_ms_from_start() {
return static_cast<__int64>(__rdtsc()/get_rdtsc_coeff());
}
如果您的系统使用SpeedStep或类似技术,则可以使用QueryPerformanceCounter / QueryPerformanceFrequency功能。 Windows保证在系统运行时频率不会改变。