Как уже говорили другие, вам действительно нужно использовать ОС реального времени, чтобы попытаться достичь этого. Точная синхронизация программного обеспечения довольно хитрая.
Однако ... хотя и не идеально, вы можете получить МНОГО лучших результатов, чем "нормальных", просто повысив приоритет процесса, который требует лучшего времени . В Windows вы можете достичь этого с помощью функции SetPriorityClass
. Если вы установите приоритет на самый высокий уровень (REALTIME_PRIORITY_CLASS: 0x00000100
), вы получите намного лучшие результаты синхронизации. Опять же - это не будет идеально, как вы просите, однако.
Это также возможно на других платформах, кроме Windows, но у меня никогда не было причин делать это, поэтому я не проверял это.
РЕДАКТИРОВАТЬ: Согласно комментарию Энди Т, если ваше приложение является многопоточным, вам также нужно следить за приоритетом, назначенным потокам. Для Windows это задокументировано здесь .
Некоторый фон ...
Некоторое время назад я использовал SetPriorityClass
, чтобы повысить приоритет приложения, в котором я выполнял анализ высокоскоростного видео в реальном времени, и я НЕ мог пропустить кадр. Кадры поступали на компьютер с очень обычной (управляемой внешним HW) частотой 300 кадров в секунду, что вызывало прерывание HW для каждого кадра, который я затем обслуживал. Поскольку синхронизация была очень важна, я собрал много статистики по времени прерывания (используя материал QueryPerformanceCounter
), чтобы увидеть, насколько на самом деле была плохая ситуация, и был потрясен полученными распределениями. У меня нет удобной статистики, но в основном Windows обслуживала прерывание всякий раз, когда ему казалось, что он работает с нормальным приоритетом. Гистограммы были очень грязными, с stdev шире, чем мой период ~ 3 мс. Часто при обработке прерываний у меня бывают гигантские промежутки в 200 мс или более (напомним, что прерывание срабатывает примерно каждые 3 мс) !! Т.е.: прерывания HW от FAR от точного! Вы застряли на том, что ОС решает сделать для вас.
Однако - когда я обнаружил настройку REALTIME_PRIORITY_CLASS
и сравнил ее с этим приоритетом, он был значительно лучше, а распределение интервалов обслуживания было очень узким. Я мог запустить 10 минут 300 кадров в секунду и не пропустить ни одного кадра. Измеренные периоды обслуживания прерываний были примерно равны 1/300 с с жестким распределением.
Кроме того - постарайтесь свести к минимуму другие действия, которые делает ОС, чтобы улучшить шансы вашего времени, работая лучше в приложении, где это важно. Например: нет перекодировки фонового видео или фрагментирования диска или чего-либо еще, пока вы пытаетесь получить точную синхронизацию с другим кодом !!
В итоге:
- Если вам это действительно нужно, используйте ОС реального времени
- Если вы не можете использовать операционную систему реального времени (невозможную или непрактичную), повышение приоритета вашего процесса, вероятно, значительно улучшит вашу синхронизацию, как это было для меня
- Прерывания HW этого не сделают ... ОС по-прежнему должна принять решение об их обслуживании!
- Убедитесь, что у вас не запущено много других процессов, конкурирующих за внимание ОС
- Если время действительно важно для вас, проведите некоторое тестирование. Хотя заставить код для выполнения точно в нужный момент не очень легко, измерить это отклонение довольно просто. Высокопроизводительные счетчики на ПК (которые вы получаете с QueryPerformanceCounter) чрезвычайно хороши.
Поскольку это может быть полезно (хотя и немного не по теме), вот небольшой класс, который я написал давным-давно для использования высокопроизводительных счетчиков на компьютере с Windows. Это может быть полезно для вашего тестирования:
CHiResTimer.h
#pragma once
#include "stdafx.h"
#include <windows.h>
class CHiResTimer
{
private:
LARGE_INTEGER frequency;
LARGE_INTEGER startCounts;
double ConvertCountsToSeconds(LONGLONG Counts);
public:
CHiResTimer(); // constructor
void ResetTimer(void);
double GetElapsedTime_s(void);
};
CHiResTimer.cpp
#include "stdafx.h"
#include "CHiResTimer.h"
double CHiResTimer::ConvertCountsToSeconds(LONGLONG Counts)
{
return ((double)Counts / (double)frequency.QuadPart) ;
}
CHiResTimer::CHiResTimer()
{
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&startCounts); // starts the timer right away
}
void CHiResTimer::ResetTimer()
{
QueryPerformanceCounter(&startCounts); // reset the reference counter
}
double CHiResTimer::GetElapsedTime_s()
{
LARGE_INTEGER countsNow;
QueryPerformanceCounter(&countsNow);
return ConvertCountsToSeconds(countsNow.QuadPart - startCounts.QuadPart);
}