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

5
如果使用一个单一的原子变量和 std::memory_order_seq_cst,那么非原子操作是否保证不会被重新排列?例如,如果我有:
std::atomic<bool> quux = {false};

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

如果我使用std::memory_order_seq_cst,那么在调用store之后bar()是否保证不会被重新排序,在调用store之前moo()是否保证不会被重新排序?至少从另一个线程的角度来看,这些假设是有效的吗?

或者,换句话说,如果从另一个线程运行以下代码,这些假设是否有效?

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都没有使用原子操作、互斥锁、锁、栅栏或其他同步特性。
3个回答

3
根据@Maxim提供的链接http://en.cppreference.com/w/cpp/atomic/memory_order,与memory_order_seq_cst有关的存在一个错误。上文应为memory_order_acq_rel。而memory_order_seq_cst的文本如下:
memory_order_seq_cst: 具有此内存顺序的加载操作执行获取操作,存储执行释放操作,并且读取-修改-写入执行获取和释放操作,同时存在单个全序,所有线程以相同顺序观察所有修改(请参见以下“顺序一致性排序”)。
因此,在您的情况下,存储操作相当于释放操作,这意味着moo()可以在栅栏之前重新排列。

我已经更新了memory_order_seq_cst的最新描述,但在我看来只有第一句话被详细说明了。我认为你关于“交换文本”的说法是不正确的。 - Maxim Egorushkin

2
如果使用单个原子变量和std::memory_order_seq_cst,非原子操作是否保证不会被重新排序?
标准在这方面非常清楚http://en.cppreference.com/w/cpp/atomic/memory_order

memory_order_seq_cst具有该存储顺序的载入操作执行获取操作,存储执行释放操作,并且读取-修改-写入执行获取操作和释放操作,加上存在一个单一的总顺序,在该顺序中,所有线程以相同的顺序观察到所有修改。

memory_order_acquire 具有此内存顺序的加载操作对受影响的内存位置执行获取操作:在此加载之前,当前线程中没有读取或写入可以被重新排序

memory_order_release 具有此内存顺序的存储操作执行释放操作:在此存储之后,当前线程中没有读取或写入可以被重新排序

换句话说,memory_order_seq_cst操作周围不能重新排序任何加载或存储(包括非原子操作和原子操作)。
“如果我使用std::memory_order_seq_cst,那么在store调用后,bar()是否保证不会被重新排序,在moo()调用前也是如此,至少从另一个线程的角度来看?”
“如果当前翻译单元中不存在bar和moo函数的定义,则编译器假定这些函数进行内存加载和/或具有副作用(执行I/O或对内存进行存储),因此不能在memory_order_seq_cst操作周围重排序。”
“如果这些函数的定义可用且这些函数没有进行I/O或内存加载/存储,则它们可以被重新排序。这些函数将是纯函数或什么都不做并返回void或常量的函数。”

有点挑剔,但是cppreference.com虽然很好,但它不是ISO标准。 - Zeta
@Zeta 你说得对。我发现cppreference.com相当准确,但可能会有遗漏,因为它不是标准的副本。 - Maxim Egorushkin

-2

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

关于if-else情况,您的结论并不完全正确。

如果表达式if(quux.load(std::memory_order_seq_cst) == true)评估为true,则函数bar肯定已经完成了调用。调用moo的顺序无法确定。它可能已经完成、尚未开始或正在进行中。

如果上述表达式评估为false,则我们无法确定两个函数的顺序。虽然在表达式评估为false时,函数moo尚未被调用,但它可能会在此之后立即被调用,在执行到else子句之前。一旦进入else子句,函数moo的状态与上一段落相同(无法确定)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接