原子变量的多重赋值是原子操作吗?
is multiple assignments of atomic variables, an atomic operation?
考虑我有两个原子布尔值,如下所示。
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>
代替?
不,不是。原子操作所保证的只是不会对变量进行干预操作。在您的示例中,完全有可能y
被分配,发生一些不相关的事情(但仅在另一个线程中;在当前线程中,由于原子上operator=
暗示的内存围栏,不会发生重新排序(,然后分配x
。阅读它们时也是如此。
如果确实希望这些操作是原子操作,则需要使用封装两条信息的单个原子类型。有很多方法可以做到这一点;您可以使用 char 并以某些位掩码操作为代价使用不同的位,您可以使用 16 位整数,但我将使用最清晰的(恕我直言(方法进行说明:具有两个布尔值的结构。
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 似乎对此进行了非常好的优化; 它将设置操作转换为单个写入 + 内存围栏,但 Clang 做得不尽如人意:https://godbolt.org/g/moiT9Y。
x = y = true; // are two bools assigned together atomically?
这条线显然不是原子操作,因为 x 和 y 位于内存中的两个不同位置:不可能同时设置两个不连续³的位置。
原子字意味着读取或写入在一个 cpu 周期¹ 内完成,因此一个变量是安全的,但 x 和 y 是两个不同的原子变量。
如果您有任何疑问,请随时查看通过使用反汇编器生成的二进制代码。
if(!x && !y) ...
相同:CPU必须通过将两个不同变量的值复制到自己的寄存器中来访问这两个变量的值,进行布尔计算,否定并执行评估²;显然不是原子操作。
¹ 它肯定不是那么简单,但从更高的语言开发者的角度来看,你应该认为
² 它又不是那么简单,因为编译器可以进行优化,而 CPU 可以自己做一些事情
³ 即使有连续的位置,总大小也必须在一个循环中可读/可写: 1Mo 的数据显然无法由 CPU 在一个循环中读取,即使所有数据都连续并排。
- C++:将值赋值给原始数据类型(例如布尔值)是原子操作吗?
- 原子变量的多重赋值是原子操作吗?
- 在C++中,当表达式涉及对象时,将表达式赋值到对象中时,是否有定义的操作顺序?
- 如何声明可以执行赋值操作的函数?(C++)
- 如何让迭代器使用赋值运算符对列表进行操作
- 为什么 GCC 拒绝复制赋值操作中的常量引用
- 为什么为单个赋值操作调用复制构造函数和重载赋值运算符
- 为什么在赋值操作完成后调用对象的析构函数
- 在一个语句中对原子布尔变量进行多次赋值
- 继承的加法赋值操作,如何返回正确的类型
- 多线程应用程序中的非原子赋值
- 赋值操作在C中隐式计算为什么布尔值
- 在c++中操作重载赋值运算符
- 编译器不使用移动 c'tor / 赋值操作器?
- 具有std::原子成员变量的类的复制构造函数/赋值运算符出错
- 没有中间对象的操作的赋值
- 赋值逻辑操作的结果
- 不带赋值运算符的位NOT操作-可能
- sort() 函数中的赋值操作
- C++11当递增原子变量,并将其赋值给其他值时,就是原子操作