©
本文档使用 PHP中文网手册 发布
_Atomic ( type-name ) | (1) | (since C11) |
---|---|---|
_Atomic type-name | (2) | (since C11) |
1)用作类型说明符; 这指定了一种新的原子类型
2)用作类型限定词; 这指定了类型名称的原子版本。在这个角色中,它可能与 const,volatile 和 restrict混合使用),但与其他限定符不同,type-name 的原子版本可能具有不同的大小,对齐和对象表示。
type-name | - | any type other than array or function. For (1), type-name also cannot be atomic or cvr-qualified |
---|
头<stdatomic.h>
定义37层便于使用的宏,从atomic_bool
到atomic_uintmax_t
,这简化使用这个关键字与内置和库类型的。
_Atomic const int * p1; // p is a pointer to an atomic const intconst atomic_int * p2; // sameconst _Atomic(int) * p3; // same
原子类型的对象是唯一没有数据竞争的对象,也就是说,它们可以被两个线程同时修改或修改一个并被另一个线程修改。
每个原子对象都有自己的关联修改顺序,这是对该对象进行修改的总顺序。如果从某个线程的角度来看,A
某些原子M的修改发生在修改B
相同的原子 M 之前,那么按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以B的修改顺序出现在M之前。
写读连贯性:如果原子对象M上的副作用X 发生在 M 的值计算B 之前,则评估B从X或从修饰顺序为M的X之后出现的副作用Y中获取其值。
一些原子操作也是同步操作; 他们可能会有额外的释放语义,获取语义或顺序一致的语义。看memory_order
。
内置增量和减量运算符和复合赋值是按顺序一致的顺序进行读 - 修改 - 写原子操作(就像使用一样memory_order_seq_cst
)。如果需要较不严格的同步语义,则可以使用标准库函数。
原子属性只对左值表达式有意义。左值到右值转换(将从原子位置读到CPU寄存器的内存建模)与其他限定符一起剥离原子性。
如果宏常量__STDC_NO_ATOMICS__
(C11)由编译器定义,则不提供关键字_Atomic
和标题<stdatomic.h>
。
访问原子结构/联合的成员是未定义的行为。
库类型sig_atomic_t
不提供线程间同步或内存排序,只有原子性。
易失性类型不提供线程间同步,内存排序或原子性。
_Atomic
.
#include <stdio.h>#include <threads.h>#include <stdatomic.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 10000The non-atomic counter is 8644