什么是timeGetTime的最佳替代品,以避免环绕?

时间:2010-05-13 09:54:46

标签: c++ windows time

timeGetTime似乎非常适合查询系统时间。但是,它的返回值仅为32位,所以每约49天就会回绕一次。

在调用代码时检测翻转并不太难,但它增加了一些复杂性,并且(更糟)需要保持状态。

是否有一些替代timeGetTime没有这种环绕问题(可能通过返回64位值),并且具有大致相同的精度和成本?

8 个答案:

答案 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 DoSomthingThatTakesLessThen49Daysduration翻身仍然是正确的。

请注意,以下代码可能会在翻转时失败。

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

可能与您正在寻找的内容相符。

http://en.cppreference.com/w/cpp/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保证在系统运行时频率不会改变。