在原子布尔变量的一个语句中多次赋值

问题描述:

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,另一个线程集btrue在读取b之前将其值分配给a,以便在指令结束时a的值为true

(这也意味着后者的版本似乎是低效率)

+2

硬盘没有看到实际的编译器输出的说旧值,但'的std ::原子::运算符=()'应该返回传递给它的价值,所以我认为'a = ...'根本不会读取'b'的值,它只会从'operator ='的输出中接收'false'。现在,在多线程情况下,当'reset()'退出时,'b'仍然可以是'true',但那是另一回事。 –

+0

@RemyLebeau好吧,那么我的问题几乎可以回答,不应该有任何区别,否则编译器会是次优的。谢谢! (当然,在'reset'结束时,如果另一个线程干预,'b'可能是'true') – Antonio

是的,有

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. 

其结果是,第二线程在反向顺序存储(a = b = false;的可观察的以下三种方式一个的变化执行原子负载(bool a_observed = a.load(); bool b_observed = b.load();) :两个b

  • 旧值a
    • 负载a,负载bba
  • b和旧值
  • 新价值a
    • b,负载aa,负载b
    • 店面b,加载a,负载b商店a
    • 负载a,存储b商店a,负载b
    • 负载a,存储b,负载b商店a
  • 为新值ba
    • 商店b,存储a,负载a,负载b

相反,memory_order_seq_cst为前b保证前a同时存储b(在其他线程)装载a以下从未观察到

    a
  • 新的价值和b
+0

谢谢,我已经测试过[这里](https:// godbolt .org/g/kozyTp)为Clang 3.8 – Antonio

Godbolt link

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

+0

非常酷的链接和网站!实际上,当使用更复杂的定义时,差别在于即使在优化时顺序也会保留https://godbolt.org/g/kozyTp – Antonio