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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了memory_order_seq_cst如何与非原子操作同步?相关的知识,希望对你有一定的参考价值。

如果使用单个原子变量和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都不使用原子操作,互斥锁,锁,围栏或其他同步功能。

答案

如果使用单个原子变量和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操作周围重新排序。


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

如果barmoo的定义在当前转换单元中不可用,则编译器假定这些函数执行内存加载和/或具有副作用(执行I / O或存储到内存),因此无法围绕memory_order_seq_cst操作重新排序。

如果定义可用且函数不执行I / O或内存加载/存储,则可以重新排序。这些将是pure functions或什么都不做的功能,并返回void或常量。

另一答案

根据由@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()。

另一答案

因为使用了最严格的内存顺序,所以函数bar和moo不能分别在商店之前或之前重新排序。

你对if-else案的结论并不完全正确。

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

如果提到的表达式求值为false,那么我们无法确定两个函数的顺序。虽然表达式的计算结果为false,但函数moo尚未被调用,可能在执行之后,在执行进入else子句之前调用它。一旦进入else子句,函数moo的状态与前一段中的状态相同(无法确定)。

以上是关于memory_order_seq_cst如何与非原子操作同步?的主要内容,如果未能解决你的问题,请参考以下文章

memory_order_seq_cst 和 memory_order_acq_rel 有何不同?

为啥在已经使用 seq_cst CAS 的无锁队列中需要 atomic_thread_fence(memory_order_seq_cst)?

Array.Sort 谷歌内核 数组大小超过10 排序字段都一致 返回的数组非原数组

文库下载器 推荐

如何将 CDialog::SetDefId 与非按钮控件一起使用?

0013-如何在Kerberos与非Kerberos的CDH集群BDR不可用时复制数据