Мое понимание std::memory_order_acquire
и std::memory_order_release
выглядит следующим образом:
Приобретать означает, что никакие обращения к памяти, которые появляются после того, как приобретаемый забор можно переупорядочить до забора,
Release означает, что после забора не могут быть переупорядочены обращения к памяти, которые появляются перед затвором.
То, что я не понимаю, - это то, почему в библиотеке атоматики С++ 11, в частности, сборщик привязок связан с операциями загрузки, в то время как забор забора связан с операциями хранилища.
Чтобы уточнить, библиотека С++ 11 <atomic>
позволяет вам указать ограждения памяти двумя способами: либо вы можете указать забор как дополнительный аргумент для атомной операции, например:
x.load(std::memory_order_acquire);
Или вы можете использовать std::memory_order_relaxed
и указать забор отдельно, например:
x.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
Что я не понимаю, учитывая приведенные выше определения получения и выпуска, почему С++ 11 специально ассоциирует приобретать с загрузкой и выпускает в магазине? Да, я видел много примеров, которые показывают, как вы можете использовать получение/загрузку с выпуском/хранилищем для синхронизации между потоками, но в целом кажется, что идея получения забора (предотвращение переопределения памяти после оператора) и выпуск забор (предотвращение переупорядочения памяти перед оператором) ортогонален идее нагрузок и хранилищ.
Итак, почему, например, компилятор не позволяет мне сказать:
x.store(10, std::memory_order_acquire);
Я понимаю, что могу выполнить выше, используя memory_order_relaxed
, а затем отдельный оператор atomic_thread_fence(memory_order_acquire)
, но опять же, почему я не могу использовать хранилище напрямую с memory_order_acquire
?
Возможно, это может быть случай использования, если я хочу убедиться, что некоторое хранилище, скажем x = 10
, происходит до того, как выполняется какой-либо другой оператор, который может повлиять на другие потоки.