В C++20 мы получили возможность засыпать атомарные переменные, ожидая изменения их значения. Мы делаем это с помощью метода std::atomic::wait
.
К сожалению, в то время как wait
стандартизирован, wait_for
и wait_until
нет. Это означает, что мы не можем спать с атомарной переменной с тайм-аутом.
Сон в атомарной переменной в любом случае реализуется за кулисами с помощью WaitOnAddress в Windows и системный вызов futex на Линукс.
Обходя вышеуказанную проблему (нет возможности спать с атомарной переменной с тайм-аутом), я мог бы передать адрес памяти std::atomic
в WaitOnAddress
в Windows, и он будет (вроде) работать без UB, так как функция получает void*
как параметр, и допустимо приведение std::atomic<type>
к void*
В Linux неясно, можно ли смешивать std::atomic
с futex
. futex
получает либо uint32_t*
, либо int32_t*
(в зависимости от того, какое руководство вы читаете), а преобразование std::atomic<u/int>
в u/int*
является UB. С другой стороны, в инструкции написано
Аргумент uaddr указывает на слово фьютекса. На всех платформах фьютексы представляют собой четырехбайтовые целые числа, которые должны быть выровнены по четырехбайтовой границе. Операция, которую необходимо выполнить над фьютексом, указывается в аргументе futex_op; val — это значение, смысл и назначение которого зависят от futex_op.
Намек на то, что alignas(4) std::atomic<int>
должно работать, и не имеет значения, какой это целочисленный тип, если тип имеет размер 4 байта и выравнивание 4.
Кроме того, я видел много мест, где реализован этот трюк с объединением атомов и фьютексов, в том числе увеличение и TBB а>.
Итак, как лучше всего спать с атомарной переменной с тайм-аутом без UB? Должны ли мы реализовать собственный атомарный класс с примитивами ОС, чтобы добиться этого правильно?
(Решения, такие как смешивание атомарных и условных переменных, существуют, но неоптимальны)
WaitOnAddress
— это ограниченная реализация условной переменной, атомарность не имеет значения. Итак, вместо использования атомарных переменных, почему бы вам не попробовать классическую условную переменную из стандартной библиотеки? - person facetus   schedule 12.04.2021WaitOnAddress
не имеет ничего общего с атомарностью, и я уверен, что не даст вам никаких преимуществ по сравнению сstd::condition_variable
.WaitOnAddress
ЯВЛЯЕТСЯ условной переменной по своей семантике, она просто скрывает за сценой явный мьютекс. Кроме того, он делает то же самое. - person facetus   schedule 18.04.2021