Другой разработчик показал мне следующий фрагмент:
std::atomic_flag lock;
// ...
while (lock.test_and_set(std::memory_order::acquire)) {}
// critical section
lock.clear(std::memory_order::release);
Я не понимаю, что здесь означает указание acquire
в качестве порядка памяти.
Это неявно тот же порядок, что и acq_rel
, или это acquire
для операции загрузки и seq_cst
(по умолчанию) для операции сохранения в рамках этой операции чтения-изменения-записи?
std::atomic_flag::test_and_set не имеет предварительных условий, и просто сказано, что:
На память влияет значение
order
.
Это ничего не проясняет для меня. Что, если order
— это acquire
? Как тогда пострадает магазин, а?
Порядки памяти описываются (только) с точки зрения их влияния на синхронизацию и последовательность.
Атомарная операция
A
, выполняющая операцию освобождения атомарного объектаM
, синхронизируется с атомарной операциейB
, которая выполняет операцию полученияM
и получает свое значение из любого побочного эффекта в последовательности освобождения, возглавляемойA
.
Влияние acquire
на «тестовую» часть test_and_set
очевидно. Что касается его влияния на «установочную» часть? Ну, у него его нет. Как и в случае с relaxed
, стандарт просто не предоставляет никаких полезных гарантий. Итак, это эквивалентно чему-то вроде memory_order::acq_relaxed
. Компилятор может перемещать чтение/запись вниз за test_and_set
, но не вверх.
В стандарте это можно прочитать так: это операция получения, но, по упущению, это не операция освобождения (поскольку об этом никогда не говорится) и она не является последовательной последовательностью.
За пределами формализма C++ рассмотрим машину LL/SC, такую как ARMv8.0: на стороне загрузки используется
ldaxr
(эксклюзивная загрузка приобретения), но на стороне хранилища просто нужна атомарность, а не упорядочивание, поэтомуstxr
неstlxr
. godbolt.org/z/M95EfsMd6 . Связанный: Для целей упорядочения атомарное чтение-изменение-запись — это одна операция или две?