【问题标题】:Multiple assignment in one statement for atomic bool variables原子布尔变量的一条语句中的多重赋值
【发布时间】:2017-10-09 22:14:17
【问题描述】:

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

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

【问题讨论】:

  • 很难说没有看到实际的编译器输出,但std::atomic::operator=() 应该返回传递给它的值,所以我认为a = ... 不会实际读取@ 的值987654335@,它只会从operator= 的输出中接收false。现在,在多线程情况下,当reset() 退出时,b 仍然可能是true,但这是另一回事。
  • @RemyLebeau 好吧,那几乎可以回答我的问题,应该没有任何区别,否则编译器将是次优的。谢谢! (当然,reset 的末尾可能是 btrue 如果另一个线程干预)

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


【解决方案1】:

是的,有区别

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.

因此,第二个线程以 reverse 存储顺序 (a = b = false;) 执行原子加载 (bool a_observed = a.load(); bool b_observed = b.load();) 可能会以以下三种方式之一观察变化

  • 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 用于在a 之前存储b 而(在另一个线程中)在b 之前加载a 保证永远不会观察到以下内容

  • a 的新值和b 的旧值

【讨论】:

  • 谢谢,我已经为 Clang 3.8 测试了 here
【解决方案2】:

Godbolt link

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

【讨论】:

  • 非常酷的链接和网站!实际上,当使用更复杂的定义时,不同之处在于即使优化后也会保留顺序godbolt.org/g/kozyTp
猜你喜欢
  • 2014-09-03
  • 2012-03-22
  • 1970-01-01
  • 2021-08-13
  • 2022-10-08
  • 2018-01-24
  • 2012-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多