Короче говоря, проблема в том, что вы вообще используете std::this_thread::sleep_for
. Или любой "сон" в этом отношении. Спать, чтобы ограничить частоту кадров, совершенно неправильно.
Цель функции сна в том, чтобы ... ну, я не знаю, если честно. У него очень мало хороших применений, и практически в любой ситуации лучше использовать другой механизм.
Что делает std::this_thread::sleep_for
(дать или принять несколько строк проверок работоспособности и проверки ошибок),он вызывает функцию Win32 Sleep
(или, в другой ОС, другую похожую функцию, такую как nanosleep
).
Теперь, что делает Sleep
? Где-то в маленькой красной книге операционной системы он отмечает, что ваш поток должен быть снова подготовлен в будущем, а затем отображает ваш поток not-ready . Быть не готовым означает просто, что ваш поток не находится в списке кандидатов, которые будут запланированы для получения процессорного времени.
Иногда, в конце концов, аппаратный таймер запускает прерывание. Это может быть периодический таймер (до Windows 8) с ужасно плохим разрешением по умолчанию или программируемое прерывание по одному кадру, что угодно. Вы даже можете настроить разрешение этого таймера, но это - глобальная вещь 1017 *, которая значительно увеличивает количество переключений контекста. Плюс, это не решает актуальную проблему . Когда ОС обрабатывает прерывание, она ищет в своей книге информацию о том, какие потоки необходимо подготовить, и делает это.
Это, однако, не то же самое, что запуск вашегонить. Это всего лишь кандидатура для повторного запуска (может быть, когда-нибудь).
Итак, есть гранулярность таймера, неточность в ваших измерениях, плюс планирование ... что в целом очень, очень не подходит для коротких периодических интервалов,Кроме того, известно, что разные версии Windows округляются по-разному в соответствии с гранулярностью планировщика.
Решение. Не спите. Включите вертикальную синхронизацию или предоставьте ее пользователю.