从Multiple assignment in one line跟进,我很想知道这对原子数据类型有什么用处,特别是对于布尔类型的例子。
假设:
class foo {
std::atomic<bool> a;
std::atomic<bool> b;
public:
void reset();
[...] //Other methods that might change a and b
}
之间有什么区别:
void foo::reset() {
a = false;
b = false;
}
和
void foo::reset() {
a = b = false;
}
即,在第二种情况下,可能会在b
被分配false
后,在b
之前将另一个线程集true
设置为b
将其值分配给a
,以便在指令结尾处a
的值为true
?
(这也意味着后一版本似乎效率较低)
答案 0 :(得分:3)
是的,
之间存在差异a = false;
b = false;
和
a = b = false;
如果a
和b
是原子的。由于赋值是从右到左完成的,后者等同于
b = false;
a = false; // since atomic::operator= (from above) returns its argument
与第一个版本不同,因为a
和b
是原子的,而assignment is done就像使用内存顺序std::atomic::store
调用memory_order_seq_cst
一样。从而,内存模型guarantees
a single total modification order of all atomic operations that are so tagged.
因此,以存储(bool a_observed = a.load(); bool b_observed = b.load();
)的 reverse 顺序执行原子加载(a = b = false;
)的第二个线程可能会观察到其中一个的变化以下三种方式:
b
和a
的旧值
a
,加载b
,b
a
b
的新值和a
的旧值
b
,加载a
,a
b
b
,加载a
,加载b
,a
a
,存储b
,a
b
a
,存储b
,加载b
,a
b
和a
的新值
b
,存储a
,加载a
,加载b
相比之下,在memory_order_seq_cst
之前存储b
a
而在a
之前加载b
(在另一个线程中)保证从未遵守以下:
a
的新值和b
答案 1 :(得分:1)
两者之间的差异很小。唯一真正的区别是分配顺序被翻转。如果启用优化,则无法区分。