Как гарантировать точный интервал ожидания потока?
Обычно, если я хочу смоделировать какую-то работу или ждать точного интервала времени, я использую condition_variable::wait_for
или на худой конец thread::this_thread::sleep_for
, Но condition_variable
документация утверждает, что wait_for
или же wait_until
методы могут блокироваться дольше, чем было запрошено.
Эта функция может блокироваться дольше, чем timeout_duration, из-за задержек планирования или конфликта ресурсов.
Каковы точные интервалы ожидания?
ОБНОВИТЬ
Могу ли я достичь этого без condition_variable
?
4 ответа
Ты не сможешь это сделать.
Чтобы получить такие точные гарантии, вам нужна операционная система реального времени.
C++ не гарантирует, что вы работаете в операционной системе реального времени.
Таким образом, он предоставляет гарантии, которые предоставляет типичная не RTOS.
Обратите внимание, что существуют другие сложности в программировании на ОСРВ, которые выходят далеко за рамки этого вопроса.
На практике, одна вещь, которую люди, когда они действительно хотят детализированное управление синхронизацией (скажем, они вертятся с буферами для каждого кадра или для каждой строки сканирования или тому подобное, или аудио буферами, или чем-то еще), это проверяют, является ли время коротким а если так, то крутись-жди. Если время больше, они ждут немного меньше времени, которое они хотят ждать, затем просыпаются и вращаются.
Это также не гарантируется, но работает достаточно хорошо почти для всех случаев.
В ОСРВ платформа может предоставлять примитивы, как вы хотите. Они выходят за рамки стандарта C++. Ни одна типичная настольная ОС не является ОСРВ, о которой я знаю. Если вы программируете аппаратное обеспечение истребителя или подобное, вы можете программировать на ОСРВ.
Я надеюсь, что вы не пишете программное обеспечение для управления истребителями и задаете этот вопрос о переполнении стека.
Это зависит от того, какую точность вы можете ожидать. Обычно, как говорили другие, обычная ОС (Linux, Windows) не может этого гарантировать.
Зачем?
Ваша ОС, вероятно, имеет концепцию потоков. Если это так, то существует планировщик, который прерывает потоки и переключает выполнение на другие потоки, ожидающие в очереди. И это может испортить точность таймеров.
Что я могу с этим поделать?
- Если вы используете встроенную систему - переходите на голое железо, то есть не используйте ОС или так называемую жесткую операционную систему реального времени.
- Если вы используете Linux, поищите в Google RT Preempt Patch. Вы должны перекомпилировать ядро, чтобы включить путь (хотя и не так сложно), а затем вы можете создавать потоки с приоритетом выше 50 - что означает приоритет над потоком ядра - что в итоге означает, что у вас может быть поток, который может прерывать планировщик и ядро в целом обеспечивает неплохую точность времени. В моем случае это то, что на три порядка (от нескольких мс задержки до нескольких нас).
- Если вы используете Windows, я не знаю о таком патче, но вы можете найти таймеры высокой точности на сайте Microsoft. Возможно, обеспеченной точности будет достаточно для ваших нужд.
С петлей грубой силы... например:
chrono::microseconds sleep_duration{1000};
auto now = chrono::high_resolution_clock::now()
while(true)
{
auto elapsed = chrono::duration_cast<hrono::microseconds>(chrono::high_resolution_clock::now() - now);
if (elapsed > sleep_duration)
break;
}
Это немного уродливо, но настольная операционная система не работает в режиме реального времени, поэтому вы не можете иметь такую точность.
Для того, чтобы расслабить процессор, вы посмотрите следующий фрагмент:
void little_sleep(std::chrono::microseconds us)
{
auto start = std::chrono::high_resolution_clock::now();
auto end = start + us;
do {
std::this_thread::yield();
} while (std::chrono::high_resolution_clock::now() < end);
}
Если вы гипотетически спали точно в течение некоторой точной продолжительности, а затем выполнили какое-то действие в ответ (например, получили текущее время или распечатали сообщение на экране), то это действие может быть отложено на некоторый неизвестный период времени, например из-за загрузка процессора. Это равносильно тому, что действие происходит (почти) немедленно, но таймер занимает больше времени, чем ожидалось. Даже в лучшем случае, когда таймер завершает работу именно в тот момент, когда вы запрашиваете, а операционная система позволяет выполнить ваше действие, не прерывая процесс, выполнение этого действия займет несколько тактов.
Другими словами, в стандартной операционной системе невозможно или даже бессмысленно завершить работу таймера именно в указанное время.
Как это можно преодолеть? Академический ответ заключается в том, что вы можете использовать специализированное программное и аппаратное обеспечение, такое как операционная система реального времени, но это значительно сложнее в разработке программного обеспечения, чем обычное программирование. Что вы, вероятно, действительно хотите знать, так это то, что в общем случае задержка, на которую ссылается эта документация, не является существенной, т.е. обычно она составляет менее 1/100 секунды.