2014-02-19 2 views
2

Я относительно новичок в программировании и im, работающем в настоящее время над проектом, который должен быть очень точным, поэтому я попытался написать что-то, чтобы создать метку времени с точностью до миллисекунды. Кажется, что это работает, но мой вопрос - это правильный путь или есть намного более простой способ? Вот мой код:timestamp in c с точностью до миллисекунд

#include<stdio.h> 
#include<time.h> 

void wait(int milliseconds) 
{ 
    clock_t start = clock(); 
    while(1) if(clock() - start >= milliseconds) break; 
} 

int main() 
{ 
    time_t now; 
    clock_t milli; 
    int waitMillSec = 2800, seconds, milliseconds = 0; 
    struct tm * ptm; 

    now = time(NULL); 
    ptm = gmtime (&now); 
    printf("time before: %d:%d:%d:%d\n",ptm->tm_hour,ptm->tm_min,ptm->tm_sec, milliseconds); 

    /* wait until next full second */ 
    while(now == time(NULL)); 

    milli = clock(); 
    /* DO SOMETHING HERE */ 
    /* for testing wait a user define period */ 
    wait(waitMillSec); 
    milli = clock() - milli; 

    /*create timestamp with milliseconds precision */ 
    seconds = milli/CLOCKS_PER_SEC; 
    milliseconds = milli%CLOCKS_PER_SEC; 
    now = now + seconds; 
    ptm = gmtime(&now); 
    printf("time after: %d:%d:%d:%d\n",ptm->tm_hour,ptm->tm_min,ptm->tm_sec, milliseconds); 
    return 0; 
} 

ответ

4

Следующий код кажется вероятным, чтобы обеспечить миллисекунды детализации:

#include <windows.h> 
#include <stdio.h> 

int main(void) { 
    SYSTEMTIME t; 
    GetSystemTime(&t); // or GetLocalTime(&t) 
    printf("The system time is: %02d:%02d:%02d.%03d\n", 
     t.wHour, t.wMinute, t.wSecond, t.wMilliseconds); 
    return 0; 
} 

Это основано на http://msdn.microsoft.com/en-us/library/windows/desktop/ms724950%28v=vs.85%29.aspx. Вышеприведенный фрагмент кода был протестирован с CYGWIN в Windows 7.

Для Windows 8 существует GetSystemTimePreciseAsFileTime, который «получает текущую системную дату и время с максимально возможным уровнем точности (< 1us)».

Ваш первоначальный подход, вероятно, будет в порядке 99,99% времени (игнорируя одну незначительную ошибку, описанную ниже). Ваш подход:

  • Ждут следующей секунды, чтобы начать, повторно набрав time(), пока значение не изменится.
  • Сохраните это значение с time().
  • Сохраните значение от clock().
  • Рассчитайте все последующие времена с использованием текущего значения clock() и двух сохраненных значений.

Ваша незначительная ошибка в том, что у вас были первые два шага в обратном порядке.

Но даже с этим исправлено, что это не гарантируется на 100%, потому что нет атомарности. Две проблемы:

  • Ваш код петли time(), пока вы не в следующую секунду. Но как далеко вы в него? Это может быть 1/2 секунды или даже несколько секунд (например, если вы используете отладчик с точкой останова).

  • Затем вы звоните clock(). Но это сохраненное значение должно «соответствовать» сохраненному значению time(). Если эти два звонка являются почти мгновенными, так как они обычно, то это нормально. Но Windows (и Linux) сокращает время, и поэтому нет никакой гарантии.

Другая проблема заключается в детализации clock. Если CLOCKS_PER_SEC равно 1000, как кажется в вашей системе, то, конечно, лучшее, что вы можете сделать, - 1 мс. Но это может быть хуже: в системах Unix обычно 15 мсек.Вы могли бы улучшить это, заменив clock на QueryPerformanceCounter(),, как в ответе на timespec equivalent for windows, но это может быть отменено с учетом первых двух проблем.

+1

Большое спасибо за ваш быстрый ответ. Я попробую это, когда вернусь к моей рабочей машине. До сих пор я не решался использовать заголовки окон. К сожалению, я должен использовать Windows XP и Visual Studio 6.0, надеюсь, это не проблема. – morten

+0

@morten: Ссылка msdn говорит, что 'GetSystemTime' доступен в Windows 2000 и выше, и я только что проверил, что он работает на моей машине XP Home SP3. Удачи, и расскажите нам, что вы делаете. –

+1

просто хотел сказать спасибо, я только что реализовал вашу идею, и все работает отлично – morten

0

Часы периодов не гарантируются в миллисекундах. Вам нужно явно преобразовать выходные данные clock() в миллисекунды.

t1 = clock(); 
// do something 
t2 = clock(); 
long millis = (t2 - t1) * (1000.0/CLOCKS_PER_SEC); 
0

Поскольку вы находитесь в Windows, почему бы вам просто не использовать Sleep()?

+0

К сожалению, я не знал об этом. Как я уже сказал, Im совершенно новый для программирования c, и мне потребовалось довольно много времени, чтобы придумать функцию ожидания :) – morten

+0

@morten - Занятые циклы излишне потребляют много CPU. Non-zero Sleep() отбрасывает текущий срез времени процесса обратно в ядро, чтобы он мог планировать запуск другого процесса. – CubicleSoft