atomic<bool>
不是多余的,因为bool
本质上是原子的吗?我认为不可能有部分修改的bool值。我何时才需要使用atomic<bool>
代替bool
?
答案 0 :(得分:81)
C ++中没有类型是“原生的”,除非它是std::atomic*
- 某种东西。那是因为标准是这样说的。
实际上,为操纵std::atomic<bool>
而发出的实际硬件指令可能(或可能不)与普通bool
相同,但是原子是一个更大的概念,更广泛分歧(例如对编译器重新排序的限制)。此外,一些操作(如否定)在原子操作上被重载,以在硬件上创建与非原子变量的本机非原子读 - 修改 - 写序列明显不同的指令。
答案 1 :(得分:59)
记住memory barriers。尽管可能无法部分更改bool
,但多处理器系统可能在多个副本中具有此变量,并且即使另一个线程已将其更改为新,一个线程也可以看到旧值。原子引入了记忆障碍,所以它变得不可能。
答案 2 :(得分:23)
C ++的原子类型处理三个潜在问题。首先,如果操作需要多个总线操作(并且可以发生在bool
,取决于它的实现方式),则可以通过任务切换来读取或写入读取或写入。其次,读取或写入可能仅影响与正在执行操作的处理器相关联的高速缓存,并且其他处理器可能在其高速缓存中具有不同的值。第三,如果编译器不影响结果,编译器可以重新排列操作的顺序(约束有点复杂,但现在已经足够了。)
您可以通过明确刷新缓存以及使用特定于编译器的选项来防止重新排序(并且,不,{{},通过假设您正在使用的类型如何实现来自行处理这三个问题中的每一个。 1}}不会这样做,除非你的编译器文档说它确实如此。
但为什么要经历这一切呢? volatile
为你照顾它,并且可能比你自己做得更好。
答案 3 :(得分:17)
原子操作不仅仅是撕裂的价值,所以虽然我同意你和其他海报的说法,我不知道可能存在撕裂bool
的环境,但还有更多的利害关系。
Herb Sutter对此进行了精彩的讨论,您可以在线查看。请注意,这是一个漫长而有牵连的谈话。 Herb Sutter, Atomic Weapons。问题归结为避免数据争用,因为它允许您具有顺序一致性的假象。
答案 4 :(得分:14)
考虑比较和交换操作:
bool a = ...;
bool b = ...;
if (a)
swap(a,b);
在我们读完之后,我们得到了真的,另一个线程可以出现并设置为假,然后我们交换(a,b),所以在退出b之后为假,即使交换已经完成。
使用std::atomic::compare_exchange
我们可以完成整个if / swap逻辑原子,这样另一个线程就无法在if和swap之间设置为false(没有锁定)。在这种情况下,如果进行交换,则b在退出时必须为假。
这只是适用于两种值类型(如bool)的原子操作的一个示例。
答案 5 :(得分:8)
某些类型的原子性完全取决于底层硬件。每个处理器体系结构对某些操作的原子性有不同的保证。例如:
Intel486处理器(以及之后的新处理器)保证以下基本内存操作始终以原子方式执行:
- 读取或写入字节
- 读取或写入在16位边界上对齐的字
- 读取或写入在32位边界上对齐的双字
其他架构对哪些操作是原子操作有不同的规范。
C ++是一种高级编程语言,力求从底层硬件中抽象出来。出于这个原因,标准根本不允许人们依赖这种低级别的假设,否则您的应用程序将无法移植。因此,C ++中的所有原始类型都由符合C ++ 11的标准库开箱即用atomic
对应物提供。