原子,from the Greek atom meaning indivisible,是“不撕裂”的代名词。这意味着整个操作不可分割地发生。
你可以用 std::atomic 类型做的所有事情都是原子的(没有撕裂)。
C++14 draft N4140 部分29.3 顺序和一致性 是该章的第一部分,详细介绍。第一点之一是(1.4):
[ 注意:指定memory_order_relaxed 的原子操作在内存排序方面是宽松的。
实现仍必须保证对特定原子对象的任何给定原子访问是不可分割的
关于对该对象的所有其他原子访问。 ——尾注]
就阐述原子性要求的技术语言而言,每个操作(如.store()、.load()、.fetch_add())都使用如下语言定义:
§ 29.6.5 对原子类型的操作要求
void atomic_store(volatile A * object, C desired) noexcept;
void atomic_store(A * object, C desired) noexcept;
void atomic_store_explicit(volatile A * object, C desired, memory_order order) noexcept;
void atomic_store_explicit(A * object, C desired, memory_order order) noexcept;
void A ::store(C desired, memory_order order = memory_order_seq_cst) volatile noexcept;
void A ::store(C desired, memory_order order = memory_order_seq_cst) noexcept;
- 要求:订单参数不得为
memory_order_consume、memory_order_acquire,也不得为
memory_order_acq_rel.
- 效果:自动替换 object 或 this 指向的值为所需的值。
根据 order 的值影响内存。
等等,在所有适用的情况下都使用原子这个词。
对于add/+、sub/- 等|、& 和 ^,它们没有重复自己,而是有一个键/操作表适用于这个块:
C atomic_fetch_key (volatile A * object, M operand) noexcept;
C atomic_fetch_key (A * object, M operand) noexcept;
C atomic_fetch_key _explicit(volatile A * object, M operand, memory_order order) noexcept;
C atomic_fetch_key _explicit(A * object, M operand, memory_order order) noexcept;
C A ::fetch_key (M operand, memory_order order = memory_order_seq_cst) volatile noexcept;
C A ::fetch_key (M operand, memory_order order = memory_order_seq_cst) noexcept;
- 28 效果:原子地替换对象所指向的值
this 将计算结果应用于指向的值
通过对象或 this 和给定的操作数。记忆受到影响
根据订单的价值。这些操作是原子的
读-修改-写操作 (1.10)。
- 29 返回:原子地,值
在效果之前由对象或 this 指向。
- 30
备注:对于有符号整数类型,算术定义为使用二进制
补表示。没有未定义的结果。地址
类型,结果可能是未定义的地址,但操作
否则没有未定义的行为。
唯一可选的是与其他线程中的加载/存储进行排序/同步(对于没有同步的原子性,请使用memory_order_relaxed)。
事实上,没有办法“关闭”原子性来加载昂贵的宽类型(例如在 x86 上的 a CAS on atomic<pointer_and_ABAcounter> which compiles to lock cmpxchg16b 之前)。我在那个答案中使用了联合黑客来有效地加载结构。
更重要的是,联合是 gcc 的一种解决方法,它不优化 ptr_and_counter.ptr 以仅加载指针,我认为至少在 x86 上是安全的。相反,gcc 坚持以原子方式加载整个结构并 然后 从结果中获取指针。当它是 x86-64 上的 16 字节结构时,这非常糟糕,而在 x86-32 上则相当糟糕。 (见https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80835)