memory_order_seq_cst 如何与非原子操作同步?

How does memory_order_seq_cst synchronize with non-atomic operations?

如果使用单个原子变量和std::memory_order_seq_cst,是否保证非原子操作不会被重新排序?

例如,如果我有

std::atomic<bool> quux = {false};

void foo() {
    bar();
    quux.store(true, std::memory_order_seq_cst);
    moo();
}

保证 bar()store 的调用之后不会被重新排序,并且 moo()store 的调用之前不会被重新排序,只要我使用std::memory_order_seq_cst,至少从另一个线程的角度来看?

或者,将其放入代码中,如果 运行 来自另一个线程,则以下假设是否有效?

if(quux.load(std::memory_order_seq_cst) == true) {
   // bar guaranteed to be called; its side-effects are visible
   // moo might have been called, but is not guaranteed to
} else {
   // bar might have been called, but is not guaranteed to
   // moo might have been called, but is not guaranteed to
}

请注意,我假设 barmoo 都不使用原子操作、互斥、锁、栅栏或其他同步功能。

If one uses a single atomic variable and std::memory_order_seq_cst, are non-atomic operations guaranteed not to be reordered?

这个标准很清楚http://en.cppreference.com/w/cpp/atomic/memory_order:

memory_order_seq_cst A load operation with this memory order performs an acquire operation, a store performs a release operation, and read-modify-write performs both an acquire operation and a release operation, plus a single total order exists in which all threads observe all modifications in the same order.

memory_order_acquire A load operation with this memory order performs the acquire operation on the affected memory location: no reads or writes in the current thread can be reordered before this load.

memory_order_release A store operation with this memory order performs the release operation: no reads or writes in the current thread can be reordered after this store.

换句话说,无法围绕 memory_order_seq_cst 操作对加载或存储(非原子和原子)进行重新排序。


is bar() guaranteed not to get reordered after the call of store, and moo() not to get reordered before the call of store, as long as I use std::memory_order_seq_cst, at least from the perspective of another thread?

如果 barmoo 的定义在当前翻译单元中不可用,编译器假定这些函数做内存加载 and/or 有副作用(做 I/O 或存储到内存),因此不能围绕 memory_order_seq_cst 操作重新排序。

如果定义可用且函数不执行 I/O 或记忆 loads/stores,则可以重新排序它们。这些将是 pure functions 或什么都不做的函数和 return void 或常数。

因为使用了最严格的内存顺序,函数 bar 和 moo 不能分别在存储到 quux 之后或之前重新排序。

您对 if-else 情况的结论不太正确。

如果表达式 if(quux.load(std::memory_order_seq_cst) == true) 的计算结果为真,那么函数 bar 肯定已经完成了它的调用。无法确定调用 moo 的顺序。它可能已经结束,没有开始,或者它可能正在通话中。

如果上述表达式的计算结果为假,那么我们无法确定这两个函数的顺序。虽然此时表达式的计算结果为假,但函数 moo 还没有被调用,它可能会在执行到 else 子句之前被调用。一旦进入else子句,函数moo的状态就和上一段一样了(无法确定)。

根据@Maxim 编辑的 link http://en.cppreference.com/w/cpp/atomic/memory_order link,上面的 memory_order_seq_cst.The 文本与 memory_order_acq_rel 交换时存在错误. memory_order_seq_cst 的文本:

memory_order_seq_cst:这个内存顺序的load操作执行acquire操作,store执行release操作,read-modify-write同时执行acquire操作和release操作,加单总存在所有线程以相同顺序观察所有修改的顺序(参见下面的 Sequentially-consistent 排序)

所以在你的例子中,存储操作等同于释放,这意味着 moo() 可以在栅栏之前重新排序。