метка времени в c с точностью до миллисекунд

Я относительно новичок в программировании на 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;
}

person morten    schedule 19.02.2014    source источник


Ответы (3)


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

#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(). Если эти два вызова почти мгновенные, как обычно, то это нормально. Но винда (да и линукс) тайм-слайс, и поэтому гарантии нет.

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

person Joseph Quinsey    schedule 20.02.2014
comment
Большое спасибо за ваш быстрый ответ. Я попробую это, когда вернусь к своей рабочей машине. До сих пор я не осмеливался использовать какие-либо заголовки Windows. К сожалению, мне приходится использовать Windows XP и Visual Studio 6.0, надеюсь, это не будет проблемой. - person morten; 20.02.2014
comment
@morten: ссылка msdn говорит, что GetSystemTime доступна в Windows 2000 и выше, и я только что убедился, что она работает на моем компьютере с XP Home SP3. Удачи, и расскажите нам, что вы в конечном итоге делаете. - person Joseph Quinsey; 20.02.2014
comment
просто хотел сказать спасибо я только что реализовал вашу идею и все работает отлично - person morten; 05.03.2014

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

t1 = clock();
// do something
t2 = clock();
long millis = (t2 - t1) * (1000.0 / CLOCKS_PER_SEC);
person Zhehao Mao    schedule 19.02.2014

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

person Markku K.    schedule 19.02.2014
comment
К сожалению, я не знал об этом. Как я уже сказал, я новичок в программировании на C, и мне потребовалось довольно много времени, чтобы придумать функцию ожидания :) - person morten; 20.02.2014
comment
@morten - Циклы занятости излишне потребляют много ресурсов ЦП. Ненулевой Sleep() возвращает ядру временной интервал текущего процесса, чтобы оно могло запланировать запуск другого процесса. - person CubicleSoft; 05.12.2015