windows 什么是 timeGetTime 的最佳替代品以避免环绕?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2825824/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the best replacement for timeGetTime to avoid wrap-around?
提问by Pawe? Hajdan
timeGetTimeseems to be quite good to query for system time. However, its return value is 32-bit only, so it wraps around every 49 days approx.
timeGetTime似乎很适合查询系统时间。但是,它的返回值仅为 32 位,因此它大约每 49 天环绕一次。
It's not too hard to detect the rollover in calling code, but it adds some complexity, and (worse) requires keeping a state.
在调用代码中检测翻转并不太难,但它增加了一些复杂性,并且(更糟糕的是)需要保持状态。
Is there some replacement for timeGetTimethat would not have this wrap-around problem (probably by returning a 64-bit value), and have roughly the same precision and cost?
是否有一些替代timeGetTime不会出现这种环绕问题(可能通过返回 64 位值),并且具有大致相同的精度和成本?
采纳答案by Hans Passant
Nope, tracking roll-over requires state. It can be as simple as just incrementing your own 64-bit counter on each callback.
不,跟踪翻转需要状态。它可以像在每次回调时增加自己的 64 位计数器一样简单。
It is pretty unusual to want to track time periods to a resolution as low as 1 millisecond for up to 49 days. You'd have to worry that the accuracy is still there after such a long period. The next step is to use the clock, GetTickCount(64), GetSystemTimeAsFileTime have a resolution of 15.625 milliseconds and are kept accurate with a time server.
想要以低至 1 毫秒的分辨率跟踪长达 49 天的时间段是非常不寻常的。您不得不担心经过这么长时间后精度仍然存在。下一步是使用时钟,GetTickCount(64)、GetSystemTimeAsFileTime 的分辨率为 15.625 毫秒,并通过时间服务器保持准确。
回答by Len Holgate
What platform?
什么平台?
You could use GetTickCount64()if you're running on Vista or later, or synthesise your own GetTickCount64()
from GetTickCount()
and a timer...
如果您在 Vista 或更高版本上运行,您可以使用GetTickCount64(),或者GetTickCount64()
从GetTickCount()
计时器合成自己的...
I deal with the rollover issue in GetTickCount()
and synthesising a GetTickCount64()
on platforms that don't support it here on my blog about testing non-trivial code: http://www.lenholgate.com/blog/2008/04/practical-testing-17---a-whole-new-approach.html
我在我的关于测试非平凡代码的博客上处理GetTickCount()
和合成GetTickCount64()
不支持它的平台上的翻转问题:http: //www.lenholgate.com/blog/2008/04/practical-testing-17 ---a-whole-new-approach.html
回答by Jerry Jongerius
Unless you need to time an event that is over 49 days, you can SAFELY ignore the wrap-around. Just always subtract the previous timeGetTime() from the current timeGetTime() and you will alwaysobtain a delta measured time that is accurate, even across wrap-around -- provided that you are timing events whose total duration is under 49 days. This all works due to how unsigned modular math works inside the computer.
除非您需要为超过 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;
TIP: look into TimeBeginPeriod(1L) to increase the accuracy of timeGetTime().
提示:查看 TimeBeginPeriod(1L) 以提高 timeGetTime() 的准确性。
BUT... if you want a 64-bit version of timeGetTime, here it is:
但是......如果你想要一个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));
}
Please note that if this function is not called at least once every 49 days, that this function will fail to properly detect a wrap-around.
请注意,如果此函数未至少每 49 天调用一次,则此函数将无法正确检测回绕。
回答by Jeremy Friesner
Assuming you can guarantee that this function will called at least once every 49 days, something like this will work:
假设你可以保证这个函数至少每 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;
}
Note that due to the use of static variables, this function isn't multithread-safe, so if you plan on calling it from multiple threads you should serialize it via a critical section or mutex or similar.
请注意,由于使用了静态变量,此函数不是多线程安全的,因此如果您计划从多个线程调用它,则应通过临界区或互斥锁或类似方法对其进行序列化。
回答by dk123
I'm not sure if this fully meets your needs, but
我不确定这是否完全满足您的需求,但是
std::chrono::system_clock
might be along the lines of what you're looking for.
可能与您要查找的内容相符。
回答by Elrohir
Have a look at GetSystemTimeAsFileTime(). It fills a FILETIME
struct that contains a "64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC)"
看看GetSystemTimeAsFileTime()。它填充一个FILETIME
结构,其中包含一个“64 位值,表示自 1601 年 1 月 1 日 (UTC) 以来 100 纳秒间隔的数量”
回答by Stephen Nutt
How are you trying to use it? I frequently use the Win32 equivalent when checking for durations that I know will be under 49 days. For example the following code will always work.
你想如何使用它?在检查我知道将在 49 天以下的持续时间时,我经常使用 Win32 等效项。例如,以下代码将始终有效。
DWORD start = timeGetTime();
DoSomthingThatTakesLessThen49Days();
DWORD duration = timeGetTime() - start;
Even if timeGetTime
rolled over while calling DoSomthingThatTakesLessThen49Days
duration
will still be correct.
即使timeGetTime
在调用时翻滚DoSomthingThatTakesLessThen49Days
duration
仍然是正确的。
Note the following code could fail on rollover.
请注意,以下代码可能会在翻转时失败。
DWORD start = timeGetTime();
DoSomthingThatTakesLessThen49Days();
if (now + 5000 < timeGetTime())
{
}
but can easy be re-written to work as follows
但可以很容易地重写为如下工作
DWORD start = timeGetTime();
DoSomthingThatTakesLessThen49Days();
if (timeGetTime() - start < 5000)
{
}
回答by Kirill V. Lyadvinsky
You could use RDTSCintrinsic. To get time in milliseconds you could get transform coefficient:
您可以使用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
}
Now you could get count of milliseconds from the last reset:
现在您可以获得上次重置的毫秒数:
__int64 get_ms_from_start() {
return static_cast<__int64>(__rdtsc()/get_rdtsc_coeff());
}
If your system uses SpeedStep or similar technologies you could use QueryPerformanceCounter/QueryPerformanceFrequencyfunctions. Windows gives guarantees then the frequency cannot change while the system is running.
如果您的系统使用 SpeedStep 或类似技术,您可以使用QueryPerformanceCounter/ QueryPerformanceFrequency函数。Windows 保证在系统运行时频率不会改变。