Как получить точный тик таймера 1 мс под WinXP - PullRequest
9 голосов
/ 29 июля 2010

Я пытаюсь вызывать функцию каждые 1 мс. Проблема в том, что мне нравится делать это с Windows. Поэтому я попробовал мультимедийный API.

Мультимедийный API

Источник

idTimer = timeSetEvent( 
     1, 
     0,
     TimerProc, 
     0, 
     TIME_PERIODIC|TIME_CALLBACK_FUNCTION ); 

Мой результат состоял в том, что большую часть времени 1 мс была в порядке, но иногда я получаю двойной период. Увидеть маленькую шишку на отметке 1,95 мс мультимедийный гистограмма http://www.freeimagehosting.net/uploads/8b78f2fa6d.png

Моей первой мыслью было, что, возможно, мой метод работал слишком долго. Но я уже измерил это, а это не так.

API очереди по таймеру

Моя следующая попытка состояла в использовании API таймера очереди с

hTimerQueue = CreateTimerQueue();
if(hTimerQueue == NULL)
{
printf("Error creating queue: 0x%x\n", GetLastError());
}

BOOL res = CreateTimerQueueTimer(
&hTimer, 
hTimerQueue, 
TimerProc, 
NULL, 
0, 
1,  // 1ms
    WT_EXECUTEDEFAULT);

Но и результат оказался не таким, как ожидалось. Теперь я получаю большую часть времени за 2 мс. queuedTimer http://www.freeimagehosting.net/uploads/2a46259a15.png

Измерение * +1021 * Для измерения времени я использовал методы QueryPerformanceCounter и QueryPerformanceFrequency. Вопрос

Итак, теперь мой вопрос: сталкивался ли кто-нибудь с подобными проблемами под Windows и, возможно, даже нашел решение?

Спасибо.

Ответы [ 3 ]

5 голосов
/ 29 июля 2010

Не переходя на ОС реального времени, вы не можете ожидать, что ваша функция будет называться каждые 1 мс.

В Windows, которая НЕ является реальнойTime OS (для Linux это похоже), программа, которая многократно считывает текущее время с точностью до микросекунды и сохраняет последовательные различия в гистограмме, имеет непустую ячейку в течение> 10 мс!Это означает, что иногда у вас есть 2 мс, но вы также можете получать больше между вашими вызовами.

1 голос
/ 12 июля 2012

Вызов NtQueryTimerResolution() вернет значение для ActualResolution .В вашем случае реальное разрешение почти наверняка составляет 0,9765625 мс.Это именно то, что вы показываете в первом сюжете.Второй интервал около 1,95 мс точнее Sleep(1) = 1,9531 мс = 2 х 0,9765625 мс

Я полагаю, что период прерывания длится примерно до 1 мс (0,9765625).

А теперь начинается проблема: таймер сигнализирует о истечении требуемой задержки.

Скажем, ActualResolution установлен на 0,9765625, сердцебиение прерывания системы будет выполняться с периодами 0,9765625 мс или 1024 Гц, и вызов Sleep будет выполнен с желаемой задержкой 1Миз.Необходимо рассмотреть два сценария:

  1. Вызов был сделан <1 мс (ΔT) перед следующим прерыванием.Следующее прерывание не подтвердит, что желаемый период времени истек.Только следующее прерывание вызовет возврат вызова.Результирующая задержка ожидания будет ΔT + 0,9765625 мс. </li>
  2. Вызов был сделан> = 1 мс (ΔT) перед следующим прерыванием.Следующее прерывание заставит звонок вернуться.Результирующая задержка сна будет ΔT.

Таким образом, результат во многом зависит от того, когда был сделан вызов, и поэтому вы можете наблюдать события 0,98 мс, а также события 1,95 мс.

Редактировать: Использование CreateTimerQueueTimer приведет к увеличению наблюдаемой задержки до 1,95, поскольку тик таймера (период прерывания) равен 0,9765625 мс.При первом возникновении прерывания запрошенная длительность в 1 мс не истекла, поэтому TimerProc будет срабатывать только после второго прерывания (2 x 0,9765625 мс = 1,9953125 мс> 1 мс).Следовательно, график queueTimer показывает пик в 1,953125 мс.

Примечание. Это поведение сильно зависит от базового оборудования.

Дополнительные сведения можно найти в проекте отметки времени Windows * 1033.*

0 голосов
/ 29 июля 2010

Вы можете попробовать запустить timeBeginPeriod (1) при запуске программы и timeEndPeriod(1) перед выходом.Это вероятно может повысить точность таймера.

...