在一个语句中为原子bool变量进行多次赋值

时间:2017-10-09 22:14:17

标签: c++ multithreading c++11 atomic

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

(这也意味着后一版本似乎效率较低)

2 个答案:

答案 0 :(得分:3)

是的,

之间存在差异
a = false;
b = false;

a = b = false;

如果ab是原子的。由于赋值是从右到左完成的,后者等同于

b = false;
a = false; // since atomic::operator= (from above) returns its argument

与第一个版本不同,因为ab是原子的,而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;)的第二个线程可能会观察到其中一个的变化以下三种方式

  • ba的旧值
    • 加载a,加载b存储b 存储a
  • b的新值和a的旧值
    • 存储b,加载a存储a ,加载b
    • 存储b,加载a,加载b存储a
    • 加载a,存储b存储a ,加载b
    • 加载a,存储b,加载b存储a
  • ba的新值
    • 存储b,存储a,加载a,加载b

相比之下,在memory_order_seq_cst之前存储b a而在a之前加载b(在另一个线程中)保证从未遵守以下

  • a的新值和b
  • 的旧值

答案 1 :(得分:1)

Godbolt link

两者之间的差异很小。唯一真正的区别是分配顺序被翻转。如果启用优化,则无法区分。