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

时间:2016-12-27 09:13:25

标签: c++ multithreading synchronization atomic

如果使用单个原子变量和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之前不会重新排序,只要我使用{ {1}},至少从另一个线程的角度来看?

或者,将它放在代码中,如果从另一个线程运行,以下假设是否有效?

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 } bar都不使用原子操作,互斥锁,锁,围栏或其他同步功能。

3 个答案:

答案 0 :(得分:3)

  

如果使用单个原子变量和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()保证在调用store之后不会重新排序,并且moo()在调用store之前不会重新排序,只要我使用std :: memory_order_seq_cst,至少从透视另一个线程?

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

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

答案 1 :(得分:2)

根据@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()可以在栅栏之前重新排序。

答案 2 :(得分:-2)

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

你对if-else案的结论不太正确。

如果表达式if(quux.load(std::memory_order_seq_cst) == true)的计算结果为true,那么功能栏肯定已经完成了它的调用。无法确定对moo的调用顺序。它可能已经完成,未启动或者可能处于通话中间。

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