Параметр упорядочения памяти при операциях с std::atomic<T>
переменными не влияет на упорядочение этой операции как таковой, он влияет на отношения упорядочения, которые операция создает с другими операциями.
напримерa.store(std::memory_order_release)
сам по себе ничего не говорит о том, как операции на a
упорядочены относительно чего-либо еще, но в паре с вызовом a.load(std::memory_order_acquire)
из другого потока, тогда этот порядок других операций -- все записи в другие переменные (включая неатомарные), выполненные потоком, который сохранил a
, видны потоку, который загрузил, если эта загрузка считывает сохраненное значение.
На современных процессорах некоторые упорядочения памяти для операций не выполняются.например, на x86 memory_order_acquire
, memory_order_consume
и memory_order_release
подразумеваются в инструкциях загрузки и хранения и не требуют отдельных заборов.В этих случаях упорядочения просто влияют на переупорядочение команд, которое может выполнить компилятор.
Разъяснение: неявные ограничения в инструкциях могут означать, что компилятору не нужно выдавать любые явные инструкции ограничения, есливсе ограничения порядка памяти привязаны к отдельным операциям над атомарными переменными.Если вы используете memory_order_relaxed
для всего и добавляете явные заборы, то компилятору, возможно, придется явно выдавать эти заборы как инструкции.
Например, на x86, инструкция XCHG
несет с собой неявную memory_order_seq_cst
забор.Таким образом, нет никакой разницы между сгенерированным кодом для двух операций обмена ниже на x86 - они оба отображаются в одну XCHG
инструкцию:
std::atomic<int> ai;
ai.exchange(3,std::memory_order_relaxed);
ai.exchange(3,std::memory_order_seq_cst);
Однако я пока не знаю ни о какихкомпилятор, который избавляется от явных инструкций забора в следующем коде:
std::atomic_thread_fence(std::memory_order_seq_cst);
ai.exchange(3,std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
Я ожидаю, что компиляторы со временем справятся с этой оптимизацией, но есть и другие подобные случаи, когда неявные ограждения позволят улучшить оптимизацию.
Кроме того, std::memory_order_consume
может только применяться к прямым операциям с переменными.