Как сделать что-то каждую миллисекунду или лучше в Windows - PullRequest
7 голосов
/ 10 августа 2011

Этот вопрос не о точной синхронизации времени в Windows (XP или лучше), а скорее о том, чтобы что-то сделать очень быстро с помощью обратного вызова или прерывания .

Мне нужно делать что-то регулярно каждую 1 миллисекунду, или, желательно, даже каждые 100 микросекунд. Что мне нужно сделать, так это подключить некоторое асинхронное оборудование (Ethernet) с такой скоростью, чтобы выводить постоянный поток пакетов в сеть и делать этот поток как можно более регулярным и синхронным. Но если вопрос можно отделить от устройства (ethernet), было бы хорошо узнать общий ответ.

Прежде чем сказать "даже не думай об использовании Windows !!!!", немного контекста. Не все системы реального времени предъявляют одинаковые требования. В большинстве случаев песни и видео воспроизводятся в Windows приемлемо, несмотря на необходимость обработки блоков аудио или изображений каждые 10-16 мс в среднем. С соответствующей буферизацией у Windows могут быть свои переменные задержки, но аппаратное обеспечение может быть широко защищено от них и поддерживать постоянный синхронный поток событий. Несмотря на это, большинство из нас терпят случайный сбой. Мое заявление такое - возможно, довольно терпимое.

Дорогой вариант для меня - перенести все приложение на Linux. Но Linux - это просто другое программное обеспечение, работающее на одном и том же оборудовании, поэтому я предпочитаю написать более качественное программное обеспечение и придерживаться Windows. У меня есть возможность избавиться от всех конкурирующих аппаратных и программных средств (без доступа к Интернету или другим сетям, других запущенных приложений и т. Д.). Есть ли у меня перспективы получить Windows для этого? С какими ограничениями я столкнусь?

Я знаю, что мое целевое оборудование имеет высокопроизводительный таймер событий и этот таймер можно запрограммировать на прерывание, но для него нет драйвера. Могу ли я написать один? Есть ли полезные примеры? Я еще не нашел один. Будет ли это мешать QueryPerformanceCounter? Означает ли тот факт, что я собираюсь использовать устройство Ethernet, все становится просто, если я использую select () разумно?

Приветствуются ссылки на полезные статьи - я нашел десятки обзоров о том, как получить точное время, но еще ни одного о том, как сделать что-то подобное, кроме использования того, что равносильно напряженному ожиданию. Есть ли способ избежать занятого ожидания? Есть ли режим ядра или опция драйвера устройства?

Ответы [ 4 ]

5 голосов
/ 10 августа 2011

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

Посмотрите здесь MSDN .

0 голосов
/ 11 августа 2011

Используйте NtSetTimerResolution при запуске программы для установки разрешения таймера.Да, это недокументированная функция, но хорошо работает.Вы также можете использовать NtQueryTimerResolution , чтобы узнать разрешение по таймеру (перед установкой и после установки нового разрешения, чтобы быть уверенным).

Вам необходимо динамически получить адрес этих функций, используя GetProcAddress изNTDLL.DLL, так как он не объявлен в заголовке или любом файле LIB.

Установка разрешения таймера таким образом повлияет на Sleep, таймеры Windows, функции, которые возвращают текущее время и т. Д.

0 голосов
/ 10 августа 2011

Если вы столкнетесь с проблемами гранулярности таймера, я бы предложил использовать старый добрый Sleep () с циклом вращения. По сути, код должен делать что-то вроде:

void PrecisionSleep(uint64 microSec)
{
    uint64 start_time;

    start_time = GetCurrentTime(); // assuming GetCurrentTime() returns microsecs

    // Calculate number of 10ms intervals using standard OS sleep.
    Sleep(10*(microSec/10000)); // assuming Sleep() takes millisecs as argument

    // Spin loop to spend the rest of the time in
    while(GetCurrentTime() - start_time < microSec)
    {}
}

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

Причина, по которой звук работает нормально на большинстве систем, заключается в том, что у аудиоустройства есть свои собственные часы. Вы просто буферируете аудиоданные к нему, и он заботится о его воспроизведении и прерывает программу, когда буфер пуст. Фактически, скачок времени между часами звуковой карты и часами ЦП может вызвать проблемы, если механизм воспроизведения использует тактовые частоты ЦП.

EDIT: Из этого можно сделать абстракцию таймера, используя поток, который использует минимальную кучу временных записей, защищенных блокировкой (сравнение кучи выполняется по метке времени истечения), а затем вы можете использовать callback () или SetEvent (), когда PrecisionSleep ) до следующей отметки времени завершается.

0 голосов
/ 10 августа 2011

Я сделал это, используя DirectX 9, используя QueryPerformanceCounter, но вам понадобится хотя бы одно ядро, так как переключение задач может испортить вам жизнь.

Для хорошего сравнения по таймеру вы можете посмотреть на

http://www.geisswerks.com/ryan/FAQS/timing.html

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