Какова лучшая замена для timeGetTime, чтобы избежать повторного использования? - PullRequest
5 голосов
/ 13 мая 2010

timeGetTime кажется неплохим для запроса системного времени. Однако его возвращаемое значение является только 32-разрядным, поэтому оно переносится каждые 49 дней.

Нетрудно обнаружить опрокидывание в вызывающем коде, но это добавляет сложности и (что еще хуже) требует сохранения состояния.

Есть ли какая-нибудь замена для timeGetTime , у которой не было бы этой проблемы с циклическим изменением (возможно, при возврате 64-битного значения), и которая имела бы примерно ту же точность и стоимость?

Ответы [ 8 ]

5 голосов
/ 04 января 2014

Если вам не нужно время для события, которое длится более 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 дней, эта функция не сможет правильно определить переход.

5 голосов
/ 13 мая 2010

Какая платформа?

Вы можете использовать GetTickCount64 () , если вы работаете в Vista или более поздней версии, или синтезировать свой собственный GetTickCount64() из GetTickCount() и таймер ...

Я имею дело с проблемой опрокидывания в GetTickCount() и синтезом GetTickCount64() на платформах, которые его не поддерживают, здесь, в моем блоге, о тестировании нетривиального кода: http://www.lenholgate.com/blog/2008/04/practical-testing-17---a-whole-new-approach.html

2 голосов
/ 13 мая 2010

Нет, для отслеживания опрокидывания требуется состояние. Это может быть так же просто, как просто увеличить свой собственный 64-битный счетчик для каждого обратного вызова.

Довольно необычно хотеть отслеживать периоды времени с разрешением до 1 миллисекунды до 49 дней. Вы должны были бы волноваться, что точность все еще там после такого длительного периода. Следующим шагом является использование часов, GetTickCount (64), GetSystemTimeAsFileTime имеют разрешение 15,625 миллисекунд и сохраняют точность на сервере времени.

1 голос
/ 14 сентября 2013

Я не уверен, полностью ли это соответствует вашим потребностям, но

std::chrono::system_clock

может быть в соответствии с тем, что вы ищете.

http://en.cppreference.com/w/cpp/chrono/system_clock

1 голос
/ 24 апреля 2013

Если вы можете гарантировать, что эта функция будет вызываться хотя бы раз в 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;
}

Обратите внимание, что из-за использования статических переменных эта функция не защищена от многопоточности, поэтому, если вы планируете вызывать ее из нескольких потоков, вы должны сериализовать ее через критическую секцию или мьютекс или аналогичное.

1 голос
/ 13 мая 2010

Как вы пытаетесь его использовать? Я часто использую эквивалент Win32 при проверке продолжительности, которая, как я знаю, будет менее 49 дней. Например, следующий код всегда будет работать.

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)
{
}
1 голос
/ 13 мая 2010

Посмотрите на GetSystemTimeAsFileTime () . Он заполняет структуру FILETIME, которая содержит «64-битное значение, представляющее число интервалов в 100 наносекунд с 1 января 1601 года (UTC)»

0 голосов
/ 13 мая 2010

Вы можете использовать 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 дает гарантии, что частота не может измениться во время работы системы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...