如果使用单个原子变量和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
都不使用原子操作,互斥锁,锁,围栏或其他同步功能。
答案 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,至少从透视另一个线程?
如果当前转换单元中没有bar
和moo
的定义,则编译器会假定这些函数执行内存加载和/或有副作用(执行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的状态与前一段中的状态相同(无法确定)。