原子 bool 变量的一条语句中的多重赋值

Multiple assignment in one statement for atomic bool variables

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之前将b设置为true被读取以将其值赋给 a,因此在指令结束时 a 的值是 true?

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

Godbolt link

两者之间的差别很小。唯一真正的区别是分配顺序被翻转了。如果你打开优化,它是无法区分的。

是的,有区别

a = false;
b = false;

a = b = false;

如果 ab 是原子的。由于赋值是从右向左进行的,所以后者相当于

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

与第一个版本不同,因为 ab 是原子的,而 assignment is done as if std::atomic::store was called with the memory order memory_order_seq_cst. Thereby, the memory model 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_csta 之前存储 b 而(在另一个线程中)在 b 之前加载 a 保证 以下从未观察到:

  • a 的新值和 b 的旧值