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

时间:2021-06-03 21:00:51

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

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

For example, if I have

例如,如果我有

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

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

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?

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

Or, to put it in code, are the following assumptions valid if run from another thread?

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

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
}

Note that I assume that neither bar nor moo use atomic operations, mutexes, locks, fences or other synchronization features.

请注意,我假设bar和moo都不使用原子操作,互斥锁,锁,围栏或其他同步功能。

3 个解决方案

#1


3  

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

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

The standard is pretty clear on this http://en.cppreference.com/w/cpp/atomic/memory_order:

该标准在http://en.cppreference.com/w/cpp/atomic/memory_order上非常清楚:

memory_order_seq_cst Any operation with this memory order is 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_seq_cst具有此内存顺序的任何操作都是获取操作和释放操作,还有一个总订单,其中所有线程都以相同的顺序观察所有修改

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_acquire使用此内存顺序的加载操作会对受影响的内存位置执行获取操作:在此加载之前,不能对当前线程中的读取或写入进行重新排序。

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_release具有此内存顺序的存储操作执行释放操作:在此存储之后,当前线程中的任何读取或写入都不能重新排序。

In other words, no loads or stores (both non-atomic and atomic) can be reordered around memory_order_seq_cst operations.

换句话说,没有任何加载或存储(非原子和原子)可以在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?

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

If the definitions of bar and moo are not available in the current translation unit, the compiler assumes that these functions do memory loads and/or have side effects (do I/O or stores to memory), and hence cannot be reordered around memory_order_seq_cst operations.

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

If the definitions are available and the functions do not do I/O or memory loads/stores then they can be reordered. These would be pure functions or functions that do nothing and return void or a constant.

如果定义可用且函数不执行I / O或内存加载/存储,则可以对它们进行重新排序。这些将是纯函数或函数,它们不执行任何操作并返回void或常量。

#2


1  

According to the link http://en.cppreference.com/w/cpp/atomic/memory_order linked by @Maxim there is an error with regards of the memory_order_seq_cst.The text above is exchanged with memory_order_acq_rel. The text for memory_order_seq_cst:

根据@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: 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 (see Sequentially-consistent ordering below)

memory_order_seq_cst:具有此内存顺序的加载操作执行获取操作,存储执行释放操作,read-modify-write执行获取操作和释放操作,以及存在单个总命令,其中所有线程都观察所有修改以相同的顺序(参见下面的顺序一致排序)

So in your case the store operation is equivalent to a release which means that moo() can be reordered before the fence.

因此,在您的情况下,存储操作等同于释放,这意味着moo()可以在栅栏之前重新排序。

#3


-2  

Because the strictest memory order is used, the functions bar and moo cannot be reordered past or before the store to quux respectively.

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

Your conclusion for the if-else case is not quite correct.

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

If the expression if(quux.load(std::memory_order_seq_cst) == true) evaluates to true, then the function bar will definitely already complete its call. The order of call to moo cannot be determined. It might have finished, not started or it could be in the middle of the call.

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

If the mentioned expression evaluates to false, then we cannot determine order for both functions. While it is true that at the moment the expression evaluates to false, the function moo hasn't been called yet, it might be called just after that, before the execution proceed to the else clause. Once in the else clause, the status of the function moo is the same as in the previous paragraph (it cannot be determined).

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

#1


3  

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

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

The standard is pretty clear on this http://en.cppreference.com/w/cpp/atomic/memory_order:

该标准在http://en.cppreference.com/w/cpp/atomic/memory_order上非常清楚:

memory_order_seq_cst Any operation with this memory order is 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_seq_cst具有此内存顺序的任何操作都是获取操作和释放操作,还有一个总订单,其中所有线程都以相同的顺序观察所有修改

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_acquire使用此内存顺序的加载操作会对受影响的内存位置执行获取操作:在此加载之前,不能对当前线程中的读取或写入进行重新排序。

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_release具有此内存顺序的存储操作执行释放操作:在此存储之后,当前线程中的任何读取或写入都不能重新排序。

In other words, no loads or stores (both non-atomic and atomic) can be reordered around memory_order_seq_cst operations.

换句话说,没有任何加载或存储(非原子和原子)可以在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?

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

If the definitions of bar and moo are not available in the current translation unit, the compiler assumes that these functions do memory loads and/or have side effects (do I/O or stores to memory), and hence cannot be reordered around memory_order_seq_cst operations.

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

If the definitions are available and the functions do not do I/O or memory loads/stores then they can be reordered. These would be pure functions or functions that do nothing and return void or a constant.

如果定义可用且函数不执行I / O或内存加载/存储,则可以对它们进行重新排序。这些将是纯函数或函数,它们不执行任何操作并返回void或常量。

#2


1  

According to the link http://en.cppreference.com/w/cpp/atomic/memory_order linked by @Maxim there is an error with regards of the memory_order_seq_cst.The text above is exchanged with memory_order_acq_rel. The text for memory_order_seq_cst:

根据@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: 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 (see Sequentially-consistent ordering below)

memory_order_seq_cst:具有此内存顺序的加载操作执行获取操作,存储执行释放操作,read-modify-write执行获取操作和释放操作,以及存在单个总命令,其中所有线程都观察所有修改以相同的顺序(参见下面的顺序一致排序)

So in your case the store operation is equivalent to a release which means that moo() can be reordered before the fence.

因此,在您的情况下,存储操作等同于释放,这意味着moo()可以在栅栏之前重新排序。

#3


-2  

Because the strictest memory order is used, the functions bar and moo cannot be reordered past or before the store to quux respectively.

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

Your conclusion for the if-else case is not quite correct.

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

If the expression if(quux.load(std::memory_order_seq_cst) == true) evaluates to true, then the function bar will definitely already complete its call. The order of call to moo cannot be determined. It might have finished, not started or it could be in the middle of the call.

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

If the mentioned expression evaluates to false, then we cannot determine order for both functions. While it is true that at the moment the expression evaluates to false, the function moo hasn't been called yet, it might be called just after that, before the execution proceed to the else clause. Once in the else clause, the status of the function moo is the same as in the previous paragraph (it cannot be determined).

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