std::atomic
原子类型是对数据的一种封装,可以防止数据竞争,达到同步多线程的内存访问的目的。对该变量的读写是原子的。
1 |
使用前需要包含头文件。该头文件中主要包含两个类:atomic 和 atomic_flag。本文主要讲解 std::atomic。
构造函数和赋值
1 | atomic() noexcept = default; |
- 构造一个未初始化的原子对象。
- 构造一个用 val 初始化的原子对象。
- 禁用拷贝构造函数,原子对象不可复制、移动。
- 可以赋值(val)。
memory_order
1 | typedef enum memory_order { |
它们的目的是为了做线程间的同步,原理是在线程内限制变量操作的顺序:
- memory_order_relaxed:用于读写,不做任何限制。
- memory_order_acquire:用于读,如果一个原子变量的 load 用了该选项,那么可以保证,在本线程内,该 load 语句之后的所有变量(不论是否原子变量)的读写语句,都实际在该 load 操作执行后执行。
- memory_order_release:用于写,如果一个原子变量的 store 用了该选项,那么可以保证,在本线程内,该 store 语句之前的所有变量(不论是否原子变量)的读写语句,都实际在该 store 操作执行前执行。
- memory_order_consume:用于读,如果一个原子变量的 load 用了该选项,那么可以保证,在本线程内,该 load 语句之后的所有依赖该变量的变量的读写语句,都实际在该 load 操作执行后执行。但是,它只保证与当前操作相关的数据依赖关系。从 2016 年后,所有编译器实现中,memory_order_consume 和 memory_order_acquire 完全一致。
- memory_order_acq_rel:memory_order_acquire + memory_order_release
- memory_order_seq_cst:sequence consistent,顺序一致,要求所有变量的读写执行顺序都和代码中的顺序一致。
memory_order_acquire 和 memory_order_release 直观上就像一个栅栏:在调用处设置一个栅栏,acquire 是拦住代码中在它后边的变量读写操作,不让其跑到它前边;release则相反,不让前边的跑到后边。(cpu 提供 memory_barrier 或者 memory_fence 指令)关于为什么 cpu 会进行内存重排,请见内存模型与内存序。
atomic::store()
1 | void store (T val, memory_order sync = memory_order_seq_cst) volatile noexcept; |
用 val 替换原子对象中的值。该操作是原子性的,通过 sync 指定内存顺序。sync 可选项见上文。
atomic::load()
1 | T load (memory_order sync = memory_order_seq_cst) const volatile noexcept; |
返回原子对象中的值。该操作为原子性。
atomic::exchange
1 | T exchange (T val, memory_order sync = memory_order_seq_cst) volatile noexcept; |
用 val 替换原子对象中的值,并返回替换前的值。操作为原子性。整个过程完成之前,其他线程无法访问。
atomic::compare_exchange_weak
1 | bool compare_exchange_weak (T &expected, T val, memory_order sync = memory_order_seq_cst) volatile noexcept; |
将原子对象的存储值和预期值比较:
- 若为 true,用 val 替换原子对象值。
- 若为 false, 用包含的值替换预期值。
整个过程是原子性的。
下面版本使用的内存顺序取决于比较结果:true 则使用 success; false 则使用 failure。该函数比较的是原子对象和预期值中的物理内容,这可能导致使用操作符 == 比较相等的值的在这里比较失败。
与 compare_exchange_strong 不同,该 weak 版本允许错误的返回 false,即使原子对象存储值与预期值相等。对于某些循环算法,这可能是可接受的行为,并且可能在某些平台上显著提高性能。对于这些虚假的失败,函数返回 false,但不修改预期的值。对于非循环算法,通常首选 compare_exchange_strong。
atomic::compare_exchange_strong
1 | bool compare_exchange_strong (T &expected, T val, memory_order sync = memory_order_seq_cst) volatile noexcept; |
原子操作。与 compare_exchange_week 不同,当期望值与对象存储的值相等时,这个强版本必须始终返回 true,不允许虚假的失败。但是,在某些机器上,对于某些在循环中检查这个的算法,compare_exchange_weak 可能有更高的性能表现。
专门化计算操作
atomic::fetch_add(T val, memory_order sync = memory_order_seq_cst)
存储的值 + val 并返回之前的值,整个操作是原子性的。如果第二个参数使用默认值,那么这个函数相当于 atomic::operator+=。
atomic::fetch_sub(T val, memory_order sync = memory_order_seq_cst)
存储的值 - val 并返回之前的值,整个操作是原子性的。如果第二个参数使用默认值,那么这个函数相当于 atomic::operator-=。
atomic::fetch_and(T val, memory_order sync = memory_order_seq_cst)
(存储的值 & val)并返回之前的值,整个操作是原子性的。如果第二个参数使用默认值,那么这个函数相当于 atomic::operator&=。
atomic::fetch_or(T val, memory_order sync = memory_order_seq_cst)
(存储的值 | val)并返回之前的值,整个操作是原子性的。如果第二个参数使用默认值,那么这个函数相当于 atomic::operator|=。
atomic::fetch_xor(T val, memory_order sync = memory_order_seq_cst)
(存储的值 ^ val)并返回之前的值,整个操作是原子性的。如果第二个参数使用默认值,那么这个函数相当于 atomic::operator^=。
atomic::operator++ ()
递增保存的值,返回递增后的值。
atomic::operator++ (int)
递增保存的值,返回递增前的值。
atomic::operator-- ()
递减保存的值,返回递减后的值。
atomic::operator-- (int)
递减保存的值,返回递减前的值。
reference:https://blog.csdn.net/u014673282/article/details/89789139