Сначала давайте посмотрим, что разрешено делать компилятору при использовании std::memory_order_relaxed
.
Если между otherStuff 1/2
и атомарной операцией нет никаких зависимостей, он, безусловно, может изменить порядок операторов. Например:
g = 3;
a.fetch_add(1, memory_order_relaxed);
g += 12;
clang ++ создает следующую сборку:
lock addl $0x1,0x2009f5(%rip) # 0x601040 <a>
movl $0xf,0x2009e7(%rip) # 0x60103c <g>
Здесь Clang позволил изменить порядок g = 3
с помощью атомарной операции fetch_add
, которая является законным преобразованием.
При использовании std::memory_order_seq_cst
вывод компилятора становится:
movl $0x3,0x2009f2(%rip) # 0x60103c <g>
lock addl $0x1,0x2009eb(%rip) # 0x601040 <a>
addl $0xc,0x2009e0(%rip) # 0x60103c <g>
Переупорядочение операторов не происходит, потому что компилятору не разрешено это делать.
Последовательное последовательное упорядочение в операции чтения-изменения-записи (RMW) является одновременно выпуском и операцией получения, и, таким образом, не допускается (видимое) переупорядочение операторов как на уровне компилятора, так и на уровне процессора.
Ваш вопрос заключается в том, является ли операция X86-64
, std::atomic::fetch_add
, использующая упрощенное упорядочение, операцией сериализации.
Ответ: да, если вы не принимаете во внимание переупорядочение компилятора.
В архитектуре X86
операция RMW всегда очищает буфер хранилища и, следовательно, является последовательной и последовательной последовательной операцией.
Можно сказать, что на X86
ЦП каждая операция RMW:
- - это операция освобождения для операций с памятью, которые предшествуют ей, и операция получения для операций с памятью, которые следуют за ней.
- становится видимым в едином общем порядке, наблюдаемом всеми потоками.