原子指令和原子类型

Atomic instructions and atomic type

本文关键字:类型 指令      更新时间:2023-10-16

默认情况下,我可以读取、修改或比较哪些类型?或者我应该为ALL操作的ALL类型显式使用原子操作吗?

是的,如果需要原子性,您应该始终使用原子类型或原子操作。从来没有什么不同。

形式上,默认情况下,没有任何非原子类型提供任何类型的原子访问。事实上,对于当前的CPU,任何内置类型都可以原子式地读写(但不能修改)。然而,这不是你有保证的,也绝对不是你应该依赖的。这只是一个实现细节
当前CPU上的所有读取和写入都通过缓存。只有完整的缓存线(通常是64-128字节左右)才能从主存中读取或写回,缓存线是最大内置类型大小的倍数。这意味着,如果一个类型正确对齐,它必然包含在一个缓存行中,这会自动使读取或写入成为原子。然而,修改值是一个读-修改-写操作,这意味着即使每个步骤都是原子的,整个操作也不是。

原子性不仅仅是能够以原子方式读取(或修改)一个值,例如,您可能需要对正确性进行排序保证。即使读写是原子的,如果不同的处理器没有按照您期望的顺序看到修改,您的代码也不会正常工作。编译器和CPU(在一些合理的限制范围内)可以重新排序指令,包括加载和存储。然而,这可能意味着您的代码将无法正确执行。

因此,原子操作有一个与之相关的"内存模型",它允许您提供关于在保证线程之间以及相关或不相关数据之间需要之前发生的事情的附加信息。有关每种模式的详细描述,请参阅GCC Wiki
默认情况下,原子操作选择顺序一致的模型,这是最安全、限制最严格的模式。如果您知道不需要某些保证,则可以选择不同的模型,这可能会(也可能不会,取决于体系结构)导致生成更高性能的代码
内存模型的好处在于,它们将实现细节、体系结构特殊性和编译器voodoo抽象成一种形式,描述您的算法需求,并保证满足这些需求。

通常,编译器将能够使用正常的非原子机器指令,并且仍然保证满足您的要求(它可能不得不放弃其中一个或另一个重新排序)。这取决于目标硬件如何工作的实际细节以及您需要什么保证
总而言之,使用原子和内存模型不仅比在低级别(内联汇编程序)手动处理更舒适,更不容易出错,而且可能是最具性能的方法。

退房http://en.cppreference.com/w/cpp/atomic/atomic.

它提到了std::atomic<T>,就像@IgorTandetnik在其中一条评论中提到的一样。