原子类型
目录 |
[编辑] 语法
_Atomic ( 类型名称 ) |
(1) | (自 C11 起) | |||||||
_Atomic 类型名称 |
(2) | (自 C11 起) | |||||||
const
、volatile
和 restrict
混合使用,但与其他限定符不同,类型名称 的原子版本可能具有不同的大小、对齐方式和对象表示形式。类型名称 | - | 除数组或函数之外的任何类型。对于 (1),类型名称 也不能是原子类型或 cvr 限定的 |
头文件 <stdatomic.h> 定义了许多方便的类型别名,从 atomic_bool 到 atomic_uintmax_t,这些别名简化了将此关键字与内置类型和库类型一起使用。
_Atomic const int* p1; // p is a pointer to an atomic const int const atomic_int* p2; // same const _Atomic(int)* p3; // same
如果编译器定义了宏常量 __STDC_NO_ATOMICS__,则不提供关键字 _Atomic。
[编辑] 解释
原子类型的对象是唯一免受数据竞争的对象;也就是说,它们可以被两个线程并发修改,或者被一个线程修改并被另一个线程读取。
每个原子对象都有其自己的关联修改顺序,这是对该对象进行的修改的总顺序。如果从某个线程的角度来看,对某个原子对象 M
的修改 A
先于 对同一原子对象 M
的修改 B
发生,则在 M
的修改顺序中,A
出现在 B
之前。
请注意,尽管每个原子对象都有其自己的修改顺序,但没有单个总顺序;不同的线程可能会以不同的顺序观察对不同原子对象的修改。
所有原子操作都保证有四种一致性
- 写-写一致性:如果修改原子对象
M
的操作A
先于 修改M
的操作B
发生,则A
在M
的修改顺序中出现在B
之前。 - 读-读一致性:如果原子对象
M
的值计算A
先于M
的值计算B
发生,并且A
从M
上的副作用X
获取其值,则B
计算的值要么是X
存储的值,要么是M
上的副作用Y
存储的值,其中Y
在M
的修改顺序中晚于X
出现。 - 读-写一致性:如果原子对象
M
的值计算A
先于M
上的操作B
发生,则A
从M
上的副作用X
获取其值,其中X
在M
的修改顺序中早于B
出现。 - 写-读一致性:如果原子对象
M
上的副作用X
先于M
的值计算B
发生,则评估B
从X
或从修改顺序中出现在X
之后的副作用Y
获取其值。
一些原子操作也是同步操作;它们可能具有额外的释放语义、获取语义或顺序一致性语义。请参阅 memory_order。
内置的 递增和递减运算符 以及 复合赋值 是具有完全顺序一致性排序的读-修改-写原子操作(就像使用 memory_order_seq_cst 一样)。如果需要不太严格的同步语义,则可以使用标准库函数代替。
原子属性仅对左值表达式有意义。左值到右值的转换(模拟从原子位置到 CPU 寄存器的内存读取)会剥离原子性以及其他限定符。
本节尚不完整 原因:更多内容,审查与 memory_order 和原子库页面的交互 |
[编辑] 注释
访问原子结构体/联合体的成员是未定义行为。
库类型 sig_atomic_t 不提供线程间同步或内存排序,仅提供原子性。
volatile
类型不提供线程间同步、内存排序或原子性。
建议实现确保 C 中 _Atomic(T) 的表示形式与 C++ 中 std::atomic<T> 的表示形式对于每种可能的类型 T
都相同。用于确保原子性和内存排序的机制应兼容。
[编辑] 关键字
[编辑] 示例
#include <stdatomic.h> #include <stdio.h> #include <threads.h> atomic_int acnt; int cnt; int f(void* thr_data) { for (int n = 0; n < 1000; ++n) { ++cnt; ++acnt; // for this example, relaxed memory order is sufficient, e.g. // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed); } return 0; } int main(void) { thrd_t thr[10]; for (int n = 0; n < 10; ++n) thrd_create(&thr[n], f, NULL); for (int n = 0; n < 10; ++n) thrd_join(thr[n], NULL); printf("The atomic counter is %u\n", acnt); printf("The non-atomic counter is %u\n", cnt); }
可能的输出
The atomic counter is 10000 The non-atomic counter is 8644
[编辑] 参考文献
- C23 标准 (ISO/IEC 9899:2024)
- 6.7.2.4 原子类型说明符 (页码:待定)
- 7.17 原子操作 <stdatomic.h> (页码:待定)
- C17 标准 (ISO/IEC 9899:2018)
- 6.7.2.4 原子类型说明符 (页码:87)
- 7.17 原子操作 <stdatomic.h> (页码:200-209)
- C11 标准 (ISO/IEC 9899:2011)
- 6.7.2.4 原子类型说明符 (页码:121)
- 7.17 原子操作 <stdatomic.h> (页码:273-286)
[编辑] 参见
并发支持库 | |
C++ 文档 关于 atomic
|