是原子操作的多个赋值,原子操作吗?

时间:2017-07-29 12:58:26

标签: c++ atomicity

考虑我有两个原子布尔如下。

private:
    std::atomic_bool x;
    std::atomic_bool y;

我可以说以下操作是原子的吗?或者我是否必须使用lock_guard来确保它们被分配在一起?

x = y = true; // are two bools assigned together atomically?

还考虑在另一个帖子中我想读这些布尔值。

if(!x && !y) ...

我的假设是,这不是原子的,或许更好地使用atomic<int>

2 个答案:

答案 0 :(得分:4)

不,不是。原子操作所保证的只是变量上没有中间操作。在您的示例中,完全有可能y被分配,不相关的事情发生(但仅在另一个线程中;在当前线程中,由于operator=隐含的内存栅栏,因此不会发生重新排序原子),然后x被分配。阅读时也是如此。

如果您真的希望这些操作是原子的,那么您需要使用封装两条信息的单一原子类型。有很多方法可以做到这一点;您可以使用char并以某些位掩码操作为代价来使用不同的位,您可以使用16位整数,但我将使用最清晰的(IMHO)方法进行说明:具有两个布尔值的结构。

struct MyBools {
  bool x;
  bool y;
};

bool operator==(const MyBools& lhs, const MyBools& rhs) {
    return lhs.x == rhs.x && lhs.y == rhs.y;
}

using MyAtomicBools = std::atomic<MyBools>;

MyAtomicBools b{true, true};
...
if (b == MyBools{false, false}) { ... }

这可能会也可能不会优化,也不会使用16位整数并手动输出两个布尔值。 gcc似乎非常好地优化了这一点;它将set操作转换为单个write +内存区域,但clang也不会这样做:https://godbolt.org/g/moiT9Y

答案 1 :(得分:2)

x = y = true; // are two bools assigned together atomically?

该行显然不是原子操作,因为x和y位于内存中的两个不同位置:不可能同时设置两个不连续的位置³彼此相同。

原子词意味着读或写是在一个cpu周期内完成的,所以一个变量是安全的,但x和y是 两个 不同的 原子变量。

如果您有任何疑问,请不要犹豫,通过使用反汇编来查看生成的二进制代码。

if(!x && !y) ...

相同:CPU必须通过复制值来访问 两个 不同 变量的值进入自己的寄存器,进行布尔评估,否定并执行评估²;显然不是原子操作。

¹肯定不是那么简单,但从高级语言开发者的角度来看,你应该认为这是 ²再次它不是那么简单,因为编译器可以进行优化,而CPU可以自己做一些事情 ³即使连续的位置,总大小必须在一个循环中可读/写:cpu在一个循环中显然不能读取1Mo数据,即使所有数据是连续并排的。