условные переменные и перевод часов
От: Кодт Россия  
Дата: 08.04.13 18:09
Оценка: 62 (7)
Прочитал на хабре интересную статью с очень важными комментариями (причём комментарии важнее!)
http://habrahabr.ru/company/nordavind/blog/175821/

Либретто:
Когда мы ждём условную переменную с таймаутом, можем нарваться на неприятный сюрприз.

Таймаут указывается не в относительных координатах (сколько миллисекунд ждать), а в абсолютных (дата и время для пробуждения).
Поэтому паттерн использования — это, грубо говоря, wait_until(...,now()+duration).

Сюрприз состоит в том, что во время ожидания системные часы могут быть подстроены, переведены на летнезимнее время или изменены пользователем.
И вместо нескольких секунд ожидание затянется хорошо если на час.

Чтобы такого не было, в pthread нужно использовать не обычные, а монотонные часы, которые всегда идут строго по возрастанию (CLOCK_MONOTONIC) и, более того, с одной скоростью (CLOCK_MONOTONIC_RAW) — разница между этими двумя часами в том, что демон NTP может вместо скачкообразного перевода часов осуществить плавную подстройку в течение некоторого времени, если величина ошибки не слишком велика.
(ветка комментариев на хабре)



Хотелось бы понять, как то же самое делается в std::condition_variable.
Да, там есть wait_for(duration) наряду с wait_until(timestamp). Но оно всё равно сделано через wait_until.
А управления ходом часов я что-то не нашёл...



Ну и, чтобы два раза не вставать.
Прекрасный комментарий про ожидание условной переменной.

Внезапные пробуждения — это вовсе не _причина_ чтобы оборачивать wait в while. Причина — это то, что ожидание извещения и ожидание состояния — это идейно разные вещи. Просто ожидать наступления определенного состояния — это делается busy loop-ом на соответствующих переменных. Но поскольку это жжет циклы процессора без особого толку, то для большинства практических случаев, где не нужно ultra-low-latency, хочется как-то эти циклы более полезно использовать. И тут возникает такой инструмент как wait(), который позволяет сказать системному планировщику задач, что вот ближайшие сколько-то времени этому потоку процессор не нужен.

Вот только исходный busy-loop от этого никуда не девается — просто внутрь него добавляется этот самый wait. То есть это не wait оборачивается в цикл — это цикл дополняется wait-ом.

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

(и ниже в ветке там объяснения для тех, кто в танке).
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.