Sleep () становится менее точным после замены ПК? (C ++) - PullRequest
4 голосов
/ 12 сентября 2009

У меня есть программа, которая была встроена в C ++ (MFC, Visual Studio 6.0) несколько лет назад и работала на определенном компьютере с Windows довольно долгое время (более 5 лет). ПК был заменен месяц назад (старый умер), и с тех пор изменились временные характеристики программы. Мне нужна помощь, чтобы понять, почему.

Основная функция программы - реагировать на нажатия клавиш, посылая сигналы ВКЛ и ВЫКЛ на внешнюю карту, с очень точной задержкой между ВКЛ и ВЫКЛ. Пример выполнения программы:

> wait for keystroke...
> ! keystroke occurred
> send ON message
> wait 150ms
> send OFF message

С разными нажатиями клавиш связаны разные периоды ожидания, от 20 мс до 150 мс (очень детерминированное время, зависящее от конкретного нажатия клавиши). Время очень важно. Ожидание выполняется с использованием простого Sleep(). Точность сна на старом ПК составляла отклонение 1-2 мс. Я могу измерить внешнее время на компьютере (на внешней карте), поэтому мое время сна очень точное. Пожалуйста, примите во внимание, что эта машина выполняла такие циклы ВКЛ-ВЫКЛ-ВЫКЛ тысячи раз в день в течение многих лет, поэтому у меня есть точные данные о точности.

Поскольку ПК был заменен, временное отклонение составляет более 10 мс.

Я не устанавливал предыдущий компьютер, поэтому на нем могут быть установлены дополнительные пакеты программного обеспечения. Кроме того, мне стыдно признаться, что я не помню, был ли предыдущий ПК Windows 2000 или Windows XP. Я совершенно уверен, что это была XP, но не 100% (и я не могу проверить сейчас ...). Новым является Windows XP.

Я пытался изменить спящий механизм на таймеры, но точность не улучшилась.

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

Ответы [ 6 ]

3 голосов
/ 12 сентября 2009

Разрешение по времени в XP составляет около 10 мс - система в основном «тикает» каждые 10 мс. Сон не очень хороший способ сделать точный выбор времени по этой причине. Я почти уверен, что win2000 имеет такое же разрешение, но если я ошибаюсь, это может быть причиной.

Вы можете изменить это разрешение, по крайней мере, до 1 мс - см. http://technet.microsoft.com/en-us/sysinternals/bb897569.aspx или использовать это http://www.lucashale.com/timerresolution/ - возможно, есть также ключ реестра (Windows Media Player также изменит этот таймер, вероятно, только пока он работает.

Может быть, разрешение каким-то образом было изменено на вашей старой машине.

2 голосов
/ 12 сентября 2009

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

1 голос
/ 13 сентября 2009

Как уже упоминали другие, сон имеет грубую точность.

Обычно я использую Boost :: asio для такого рода синхронизации:

// Set up the io_service and deadline_timer
io_service io_
deadline_timer timer(io_service);

// Configure the wait period
timer.expires_from_now(posix_time::millisec(5));
timer.wait();

Asio использует наиболее эффективную реализацию для вашей платформы; в Windows я полагаю, что он использует перекрывающийся ввод-вывод.

Если я установлю период времени на 1 мс и зациклю "таймер". звонки 10000 раз, длительность обычно составляет около 10005-10100 мс. Очень точный кроссплатформенный код (хотя точность в Linux отличается) и очень легко читаемый.

Я не могу объяснить, почему ваш предыдущий компьютер был настолько точным; Время сна составляло +/- 10 мс всякий раз, когда я его использовал - хуже, если компьютер занят.

1 голос
/ 13 сентября 2009

Обычно Sleep () приводит к задержке ~ 15 мс или периоду, кратному ~ 15 мс в зависимости от значения сна. Один из хороших способов выяснить, как это работает - следующий псевдокод:

while true do
    print(GetTickCount());
    Sleep(1);
end;

А также покажет, что поведение этого кода отличается, скажем, для Windows XP и Vista / Win 7

0 голосов
/ 12 сентября 2009

Ваш новый ПК многоядерный и старый одноядерный? Разница в точности синхронизации может заключаться в использовании нескольких потоков и переключении контекста.

0 голосов
/ 12 сентября 2009

Сон зависит от системных часов. Ваша новая машина, вероятно, имеет другое время, чем ваша предыдущая машина. Из документации :

Эта функция заставляет поток отказаться от оставшейся части своего времени нарезать и стать непригодным для интервал на основе значения dwMilliseconds. Системные часы «тикает» с постоянной скоростью. Если dwMilliseconds меньше, чем разрешение системных часов, нить может спать меньше чем указанная продолжительность времени. Если dwMilliseconds больше единицы тик, но меньше двух, ожидание может быть где-то между одним и двумя тиками, и так далее. Чтобы повысить точность интервал сна, позвоните Функция timeGetDevCaps для определения поддерживаемое минимальное разрешение таймера и функция timeBeginPeriod для установить разрешение таймера на его минимум. Будьте осторожны при звонке timeBeginPeriod, так как частые звонки могут существенно повлиять на системные часы, энергопотребление системы и планировщик. Если вы вызываете timeBeginPeriod, вызывайте его один раз в начале заявки и обязательно вызовите timeEndPeriod функция в самом конце применение.

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

Какими таймерами вы его заменили? Если вы использовали SetTimer (), этот таймер тоже отстой.
Правильное решение - использовать более высокое разрешение TimerQueueTimer .

...