Магазин с std::memory_order_release
в какое-то место можно переупорядочить с последующей загрузкой из другого места с помощью std::memory_order_acquire
,
Но может магазин с std::memory_order_release
в каком-то месте будет переупорядочен с последующей загрузкой из другого места с std::memory_order_seq_cst
?
Аналогично, может магазин с std::memory_order_seq_cst
на переменную переупорядочить с последующей загрузкой из другого места с std::memory_order_acquire
?
Рассмотрим этот пример:
std::atomic<int> x{0};
std::atomic<int> y{0};
void thread1() {
x.store(std::memory_order_release, 1);
int r1 = y.load(std::memory_order_seq_cst);
std::cout << r1 << std::endl;
}
void thread2() {
y.store(std::memory_order_seq_cst, 1);
int r2 = x.load(std::memory_order_acquire);
std::cout << r2 << std::endl;
}
Это хорошо известно (http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/) что если оба std::memory_order_seq_cst
были заменены их аналогом освобождения / приобретения, выход может быть в два раза больше «0».
Покупает ли последовательная согласованность что-нибудь в этом примере, или результат может все еще быть два раза «0»?
Нет, последовательная согласованность ничего не покупает в этом примере, и результат все равно может быть в два раза больше «0».
Единственная разница между std::memory_order_seq_cst
а также std::memory_order_acquire/release
в том, что std::memory_order_seq_cst
магазины не могут быть переупорядочены с последующим std::memory_order_seq_cst
загружает в разные переменные / местоположения, см. «атомное» Херба Саттера<> «Оружие». (Конечно, может случиться так, что магазины не будут переупорядочены с последующей загрузкой в ту же переменную.)
Но, как только ослабнет только один (не говоря уже о обоих) порядки памяти (как в обоих потоках в примере), может произойти переупорядочение StoreLoad. Это означает, что в примере обе нагрузки могут быть переупорядочены перед их соответствующим хранением.
Это означает, что программа, которая содержит только один std::memory_order_seq_cst
а иначе только std::memory_order_release/acquire
остается той же программой, если один должен был заменить одинокий std::memory_order_seq_cst
от std::memory_order_release
(если это с магазином) или std::memory_order_acquire
(если это с грузом).