Предоставляет ли стандарт С++ 11, что memory_order_seq_cst
предотвращает переупорядочение StoreLoad вокруг атомной операции для доступа к неатомной памяти?
Как известно, в С++ 11 есть 6 std::memory_order
, и в нем указано , как регулярные, неатомные обращения к памяти должны быть упорядочены вокруг атомной операции - Рабочий проект, Стандарт для Язык программирования С++ 2016-07-12: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf
§ 29.3 Порядок и согласованность
§ 29.3/1
В перечислении memory_order указан подробный регулярный (неатомной) памяти, как определено в 1.10, и может обеспечить порядок работы. Его перечисляемые ценности и их значения следующие:
Также известно, что эти 6 memory_orders предотвращают некоторые из этих переупорядочений:
Но, memory_order_seq_cst
предотвращает переупорядочение StoreLoad вокруг атомарной операции для регулярных, неатомных регулярных, неатомических запросов к памяти или только для других атомов с тем же memory_order_seq_cst
?
т.е. чтобы предотвратить переупорядочение StoreLoad, мы должны использовать std::memory_order_seq_cst
для STORE и LOAD или только для одного из них?
std::atomic<int> a, b;
b.store(1, std::memory_order_seq_cst); // Sequential Consistency
a.load(std::memory_order_seq_cst); // Sequential Consistency
О семантике Acquire-Release все ясно, он указывает точно неатомное переупорядочение доступа к памяти в рамках атомных операций: http://en.cppreference.com/w/cpp/atomic/memory_order
Чтобы предотвратить переупорядочение StoreLoad, мы должны использовать std::memory_order_seq_cst
.
Два примера:
-
std::memory_order_seq_cst
для STORE и LOAD: естьMFENCE
StoreLoad не может быть переупорядочен - GCC 6.1.0 x86_64: https://godbolt.org/g/mVZJs0
std::atomic<int> a, b;
b.store(1, std::memory_order_seq_cst); // can't be executed after LOAD
a.load(std::memory_order_seq_cst); // can't be executed before STORE
-
std::memory_order_seq_cst
только для LOAD: нетMFENCE
StoreLoad можно переупорядочить - GCC 6.1.0 x86_64: https://godbolt.org/g/2NLy12
std::atomic<int> a, b;
b.store(1, std::memory_order_release); // can be executed after LOAD
a.load(std::memory_order_seq_cst); // can be executed before STORE
Также, если C/С++ - компилятор использовал альтернативное отображение C/С++ 11 на x86, которое сбрасывает буфер хранения до LOAD: MFENCE,MOV (from memory)
, поэтому мы также должны использовать std::memory_order_seq_cst
для LOAD: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html Поскольку этот пример обсуждается в другом вопросе как подход (3): Имеет ли смысл какую-либо команду LFENCE в процессорах x86/x86_64?
т.е. мы должны использовать std::memory_order_seq_cst
как для STORE, так и для LOAD для создания MFENCE
гарантированного, что предотвращает переупорядочение StoreLoad.
Это правда, что memory_order_seq_cst
для атомной загрузки или сохранения:
-
speci Приобретать-освобождать семантику - предотвращать: LoadLoad, LoadStore, StoreStore переупорядочивает вокруг атомной операции для регулярных, неатомических доступа к памяти,
-
но не препятствуйте StoreLoad переупорядочивать вокруг атомной операции только для других атомных операций с тем же
memory_order_seq_cst
?