atomic
是STL(标准库)
中的一个头文件, 定义了 C++11标准中的一些表示 线程并发控制
时 原子操作
的类与方法. 主要声明了两个类模板: std::atomic
和 std::atomic_flag
, 另外还声明了一套C风格的原子类型
与 C兼容的原子操作
的函数.
在多线程并发执行时, 原子操作
是线程不会打断的执行片段. 一些程序设计更为注重性能和效率, 需要开发 lock-free
的算法与数据结构, 这就需要更为底层的 原子操作
与 原子类型
. 原子类型
对象的主要特点就是从不同的线程并发访问是 良性(well-defined) 行为, 不会导致 竞争危害. 与之相反, 不做适当控制就并发访问 非原子对象
则会导致 未定义(undefined) 行为.
仅靠原子指令
实现不了对资源的访问控制. 这造成的原因是编译器和cpu实施了重排指令, 导致读写
顺序会发生变化, 只要不存在依赖, 代码中后面的指令可能会被放在前面, 从而先执行它. cpu这么做是为了尽量塞满每个时钟周期, 在单位时间内尽量执行更多的指令, 从而提高吞吐率.
我们先来看两个线程代码:
// thread 1
// flag初始值为false
a.init();
flag = true;
// thread 2
if(flag) {
a.bar();
}
线程2在ready为true的时候会访问p, 对线程1来说, 如果按照正常的执行顺序, 那么p先被初始化, 然后在将ready赋为true. 但对多核的机器而言, 情况可能有所变化:
- 线程1中的
ready = true
可能会被CPU或编译器 重排序
到 p.init()
的前面, 从而优先执行 ready = true
这条指令. 在线程2中, p.bar()
中的一些代码可能被重排到 if(ready)
之前.
- 即使没有
重排序
, ready和p的值也会独立地同步到线程2所在核心的cache, 线程2仍然可能在看到ready为true时看到未初始化的p.
为了解决这个问题, 我们一种解决方法是使用互斥元
, 还有一种就是CPU和编译器提供了memory fence
, 让用户可以声明访存指令的可见性关系, C++11总结为以下memory order
内存序模型
是讨论在 原子操作
附近的 读写
操作顺序
typedef enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst
} memory_order;
enum class memory_order : {
relaxed, consume, acquire, release, acq_rel, seq_cst
};
inline constexpr memory_order memory_order_relaxed = memory_order::relaxed;
inline constexpr memory_order memory_order_consume = memory_order::consume;
inline constexpr memory_order memory_order_acquire = memory_order::acquire;
inline constexpr memory_order memory_order_release = memory_order::release;
inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel;
inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst;
-
memory_order_relaxed
: 只保证 原子操作
的 原子性 .
无fencing
作用, CPU和编译器 可以 重排序
指令
-
memory_order_consume
: 使用这种 内存序
的 读
操作在被影响的内存位置上执行consume
操作:
- 当前线程依赖于这个当前
读取
值的 读写
操作 不能 重排序
到这条 读
操作之前;
写
这个 原子变量
的其他线程的数据依赖变量的 写入
对当前线程 可见 .
- 在大多数平台, 这 只影响 编译器的行为.
后面 依赖此 原子变量
的访存指令 不能 重排序
至此条指令之前
-
memory_order_acquire
: 使用这种 内存序
的 读
操作在被影响的内存位置上执行acquire
操作:
- 当前线程的
读写
不能 被 重排序
在这条 读
操作之前.
- 其他线程对这个
原子变量
的所有 写
操作对当前线程是 可见 的.
后面 依赖此 原子变量
的访存指令 不能 重排序
至此条指令之前
-
memory_order_release
: 使用这种 内存序
的 写
操作在被影响的内存位置上执行release
操作:
- 当前线程的
读写
不能被 重排序
在这条 读
操作之后.
- 当前线程的所有
写
操作对其他 读
这个 原子变量
的线程是 可见 的.
- 导致这个
原子变量
依赖的 写
操作对于其他 consume
这个 原子变量
的线程是 可见 的.
前面 依赖此 原子变量
的访存指令 不能 重排序
到此条指令之后. 当此条指令的结果被同步到其他核的cache中时, 保证前面的指令也已经被同步.
-
memory_order_acq_rel
: 使用这种 内存序
的一个 read-modify-write
操作既是 acquire
操作也是 release
操作. 当前线程的 读写
不能 被 重排序
在这条操作之前以及之后. 其他线程对这个 原子变量
的 release
对本线程是 可见 的. 本线程的这条操作结果对其他 读取
该 原子变量
的线程是 可见 的.
acquare
+ release
-
memory_order_seq_cst
: 使用这种 内存序
的 读
操作在被影响的内存位置上执行 acquire
操作, 使用这种 内存序
的 写
操作在被影响的内存位置上执行 release
操作, 使用这种 内存序
的一个 read-modify-write
操作既是 acquire
操作也是 release
操作. 并存在一个全序, 所有线程看到的所有修改是同样的顺序.
acquare
+ release
+ 所有使用 memory_order_seq_cst
的指令有严格的全序关系
有了 memory_order
, 我们可以这么改上面的例子:
// thread 1
// flag初始值为false
a.init();
flag.store(true, std::memory_order_release); //前面的不能在我后面执行
// thread 2
if(flag.load(std::memory_order_acquire)) { //后面的不能在我前面执行
a.bar();
}
这样就保证了线程1和线程2的顺序性, 比如线程2在看到flag==true
时, 能看到线程1 realse
之前所有操作. 也就保证了代码符合我们的预期.
注意 : memory fence(内存栅栏)
不等于可见性, 即使线程2恰好在线程1在把flag设置为true后读取了flag也不意味着它能看到true, 因为同步cache是有延时的. memory fence
保证的是可见性的顺序: "假如我看到了a的最新值, 那么我一定也得看到b的最新值".
atomic_flag
是一种简单的原子布尔类型
, 只支持两种操作: test_and_set
和 clear
.
结合 std::atomic_flag::test_and_set()
和 std::atomic_flag::clear()
, std::atomic_flag
对象可以当作一个简单的自旋锁(spin lock)
使用.
atomic_flag() noexcept = default;
atomic_flag (const atomic_flag&T) = delete;
移动构造函数实际上也禁用. 根据C++标准的一般规定, 如果一个类显式声明了拷贝构造函数(即使是作为delete), 就不会有缺省的移动构造函数.
相关的宏:如果在初始化时没有明确使用宏ATOMIC_FLAG_INIT
初始化, 那么新创建的std::atomic_flag
对象的状态是 未指定的(unspecified)
, 既没有被 set
也没有被 clear
; 如果使用该宏初始化, 该 std::atomic_flag
对象在创建时处于 clear
状态.
bool test_and_set (memory_order sync = memory_order_seq_cst) volatile noexcept;
bool test_and_set (memory_order sync = memory_order_seq_cst) noexcept;
void clear (memory_order sync = memory_order_seq_cst) volatile noexcept;
void clear (memory_order sync = memory_order_seq_cst) noexcept;
示例
#include <iostream>
#include <atomic>
#include <vector>
#include <thread>
#include <sstream>
std::atomic_flag lock = ATOMIC_FLAG_INIT;
std::stringstream stream;
int main() {
std::vector<std::thread> vec_thread;
for ( int i = 0; i < 10; i++ ) {
vec_thread.push_back( std::thread( [](int x){
while ( lock.test_and_set() );
stream << "thread#" << x << " \n ";
lock.clear();
}, i));
}
for ( int i = 0; i < 10; i++ ){
vec_thread[i].join();
}
std::cout << stream.str();
return 0;
}
bool atomic_flag_test_and_set (volatile atomic_flag* obj) noexcept;
bool atomic_flag_test_and_set (atomic_flag* obj) noexcept;
bool atomic_flag_test_and_set (volatile atomic_flag* obj, memory_order sync) noexcept;
bool atomic_flag_test_and_set (atomic_flag* obj, memory_order sync) noexcept;
void atomic_flag_clear (volatile atomic_flag* obj) noexcept;
void atomic_flag_clear (atomic_flag* obj) noexcept;
void atomic_flag_clear (volatile atomic_flag* obj, memory_order sync) noexcept;
void atomic_flag_clear (atomic_flag* obj, memory_order sync) noexcept;
std::atomic
比 std::atomic_flag
功能更加完善, 因此有更多的成员方法.
template < class T > struct atomic {
// 缺省构造, std::atomic 对象处于未初始化(uninitialized)状态
atomic() = default;
// 普通构造函数, 由类型T初始化一个 std::atomic对象
constexpr atomic(T)) noexcept;
// 禁止拷贝构造
atomic(const atomic &) = delete;
// 禁止拷贝赋值
atomic & operator=(const atomic &) = delete;
atomic & operator=(const atomic &) volatile = delete;
// 从类型T的隐式转换赋值
T operator=(T) volatile noexcept;
T operator=(T) noexcept;
// 判断该 std::atomic对象是否具备lock-free的特性. 如果某个对象满足 lock-free 特性, 在多个线程访问该对象时不会导致线程阻塞.
bool is_lock_free() const volatile;
bool is_lock_free() const;
// 修改被封装的值, 参数 sync 指定内存序
void store(T, memory_order = memory_order_seq_cst) volatile;
void store(T, memory_order = memory_order_seq_cst);
// 读取被封装的值, 参数 sync 设置内存序
T load(memory_order = memory_order_seq_cst) const volatile;
T load(memory_order = memory_order_seq_cst) const;
// 与load()的功能类似, 也是读取被封装的值
operator T() const volatile;
operator T() const;
// 读取并修改被封装的值, 用val指定的值替换该原子对象封装的值, 并返回该原子对象之前封装的值, 整个过程是原子的, 因此exchange 操作也称为 read-modify-write 操作.
T exchange(T, memory_order = memory_order_seq_cst) volatile;
T exchange(T, memory_order = memory_order_seq_cst);
// 比较被封装的值(weak)与参数expected所指定的值的物理内容是否相等, 如果相等, 则用val替换原子对象的旧值;如果不相等, 则用原子对象的旧值替换expected.
// 因此调用该函数之后, 如果被该原子对象封装的值与参数 expected 所指定的值不相等, expected 中的内容就是原子对象的旧值.
// 整个操作是原子的, 当前线程读取和修改该原子对象时, 别的线程不能对读取和修改该原子对象.
// 与compare_exchange_strong不同, weak版本的compare-and-exchange操作允许spuriously 返回 false, 即原子对象所封装的值与参数 expected 的物理内容相同, 但却仍然返回 false, 这在使用循环操作的算法下是可以接受的, 并且在一些平台下weak版本的性能更
bool compare_exchange_weak (T& expected, T val, memory_order sync = memory_order_seq_cst) volatile noexcept;
bool compare_exchange_weak (T& expected, T val, memory_order sync = memory_order_seq_cst) noexcept;
// 功能同上. 内存序(Memory Order)的选择取决于比较操作结果, 如果比较结果为 true(即原子对象的值等于 expected), 则选择参数 success 指定的内存序, 否则选择参数 failure 所指定的内存序.
bool compare_exchange_weak (T& expected, T val, memory_order success, memory_order failure) volatile noexcept;
bool compare_exchange_weak (T& expected, T val, memory_order success, memory_order failure) noexcept;
// 与weak版本的差别在于, 如果原子对象所封装的值与参数 expected 的物理内容相同, 比较操作一定会为 true.
bool compare_exchange_strong(T &, T, memory_order = memory_order_seq_cst) volatile;
bool compare_exchange_strong(T &, T, memory_order = memory_order_seq_cst);
bool compare_exchange_strong(T &, T, memory_order, memory_order) volatile;
bool compare_exchange_strong(T &, T, memory_order, memory_order);
};
C++11标准库std::atomic
提供了针对整形(integral)
和指针类型的特化实现.
针对整形(integal)
的特化, 其中integal
代表了如下类型 char
, signed char
, unsigned char
, short
, unsigned short
, int
, unsigned int
, long
, unsigned long
, long long
, unsigned long long
, char16_t
, char32_t
, wchar_t
:
template <> struct atomic<integral> {
bool is_lock_free() const volatile;
bool is_lock_free() const;
void store(integral, memory_order = memory_order_seq_cst) volatile;
void store(integral, memory_order = memory_order_seq_cst);
integral load(memory_order = memory_order_seq_cst) const volatile;
integral load(memory_order = memory_order_seq_cst) const;
operator integral() const volatile;
operator integral() const;
integral exchange(integral, memory_order = memory_order_seq_cst) volatile;
integral exchange(integral, memory_order = memory_order_seq_cst);
bool compare_exchange_weak(integral&, integral, memory_order, memory_order) volatile;
bool compare_exchange_weak(integral&, integral, memory_order, memory_order);
bool compare_exchange_strong(integral&, integral, memory_order, memory_order) volatile;
bool compare_exchange_strong(integral&, integral, memory_order, memory_order);
bool compare_exchange_weak(integral&, integral, memory_order = memory_order_seq_cst) volatile;
bool compare_exchange_weak(integral&, integral, memory_order = memory_order_seq_cst);
bool compare_exchange_strong(integral&, integral, memory_order = memory_order_seq_cst) volatile;
bool compare_exchange_strong(integral&, integral, memory_order = memory_order_seq_cst);
//原子对象的封装值加 val, 并返回原子对象的旧值. 整个过程是原子的
integral fetch_add(integral, memory_order = memory_order_seq_cst) volatile;
integral fetch_add(integral, memory_order = memory_order_seq_cst);
integral fetch_sub(integral, memory_order = memory_order_seq_cst) volatile;
integral fetch_sub(integral, memory_order = memory_order_seq_cst);
integral fetch_and(integral, memory_order = memory_order_seq_cst) volatile;
integral fetch_and(integral, memory_order = memory_order_seq_cst);
integral fetch_or(integral, memory_order = memory_order_seq_cst) volatile;
integral fetch_or(integral, memory_order = memory_order_seq_cst);
integral fetch_xor(integral, memory_order = memory_order_seq_cst) volatile;
integral fetch_xor(integral, memory_order = memory_order_seq_cst);
atomic() = default;
constexpr atomic(integral);
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
integral operator=(integral) volatile;
integral operator=(integral);
integral operator++(int) volatile; //后缀++
integral operator++(int);
integral operator--(int) volatile; //后缀--
integral operator--(int);
integral operator++() volatile; //前缀++
integral operator++();
integral operator--() volatile; //前缀--
integral operator--();
integral operator+=(integral) volatile;
integral operator+=(integral);
integral operator-=(integral) volatile;
integral operator-=(integral);
integral operator&=(integral) volatile;
integral operator&=(integral);
integral operator|=(integral) volatile;
integral operator|=(integral);
integral operator^=(integral) volatile;
integral operator^=(integral);
};
针对指针的特化:
template <class T> struct atomic<T*> {
bool is_lock_free() const volatile;
bool is_lock_free() const;
void store(T*, memory_order = memory_order_seq_cst) volatile;
void store(T*, memory_order = memory_order_seq_cst);
T* load(memory_order = memory_order_seq_cst) const volatile;
T* load(memory_order = memory_order_seq_cst) const;
operator T*() const volatile;
operator T*() const;
T* exchange(T*, memory_order = memory_order_seq_cst) volatile;
T* exchange(T*, memory_order = memory_order_seq_cst);
bool compare_exchange_weak(T*&, T*, memory_order, memory_order) volatile;
bool compare_exchange_weak(T*&, T*, memory_order, memory_order);
bool compare_exchange_strong(T*&, T*, memory_order, memory_order) volatile;
bool compare_exchange_strong(T*&, T*, memory_order, memory_order);
bool compare_exchange_weak(T*&, T*, memory_order = memory_order_seq_cst) volatile;
bool compare_exchange_weak(T*&, T*, memory_order = memory_order_seq_cst);
bool compare_exchange_strong(T*&, T*, memory_order = memory_order_seq_cst) volatile;
bool compare_exchange_strong(T*&, T*, memory_order = memory_order_seq_cst);
T* fetch_add(ptrdiff_t, memory_order = memory_order_seq_cst) volatile;
T* fetch_add(ptrdiff_t, memory_order = memory_order_seq_cst);
T* fetch_sub(ptrdiff_t, memory_order = memory_order_seq_cst) volatile;
T* fetch_sub(ptrdiff_t, memory_order = memory_order_seq_cst);
atomic() = default;
constexpr atomic(T*);
atomic(const atomic&) = delete;
atomic& operator=(const atomic&) = delete;
atomic& operator=(const atomic&) volatile = delete;
T* operator=(T*) volatile;
T* operator=(T*);
T* operator++(int) volatile;
T* operator++(int);
T* operator--(int) volatile;
T* operator--(int);
T* operator++() volatile;
T* operator++();
T* operator--() volatile;
T* operator--();
T* operator+=(ptrdiff_t) volatile;
T* operator+=(ptrdiff_t);
T* operator-=(ptrdiff_t) volatile;
T* operator-=(ptrdiff_t);
};
范例
#include <iostream>
#include <atomic>
#include <vector>
#include <thread>
#include <sstream>
std::atomic<int> foo(0);
void set_foo(int x){
foo = x;
}
void print_foo(){
while (foo == 0) {
std::this_thread::yield();
}
std::cout << "x: " << foo << std::endl;
}
int main() {
std::thread print_th(print_foo);
std::thread set_th(set_foo, 10);
print_th.join();
set_th.join();
return 0;
}
template <class T> bool atomic_is_lock_free (const volatile atomic<T>* obj) noexcept;
template <class T> bool atomic_is_lock_free (const atomic<T>* obj) noexcept;
bool atomic_is_lock_free (const volatile A* obj) noexcept;
bool atomic_is_lock_free (const A* obj) noexcept;
template <class T> void atomic_init (volatile atomic<T>* obj, T val) noexcept;
template <class T> void atomic_init (atomic<T>* obj, T val) noexcept;
void atomic_init (volatile A* obj, T val) noexcept;
void atomic_init (A* obj, T val) noexcept;
template <class T> void atomic_store (volatile atomic<T>* obj, T val) noexcept;
template <class T> void atomic_store (atomic<T>* obj, T val) noexcept;
void atomic_store (volatile A* obj, T val) noexcept;
void atomic_store (A* obj, T val) noexcept;
template <class T> T atomic_load (const volatile atomic<T>* obj) noexcept;
template <class T> T atomic_load (const atomic<T>* obj) noexcept;
T atomic_load (const volatile A* obj) noexcept;
T atomic_load (const A* obj) noexcept;
template <class T> T atomic_load_explicit (const volatile atomic<T>* obj, memory_order sync) noexcept;
template <class T> T atomic_load_explicit (const atomic<T>* obj, memory_order sync) noexcept;
T atomic_load_explicit (const volatile A* obj, memory_order sync) noexcept;
T atomic_load_explicit (const A* obj, memory_order sync) noexcept;
template <class T> T atomic_exchange (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_exchange (atomic<T>* obj, T val) noexcept;
T atomic_exchange (volatile A* obj, T val) noexcept;
T atomic_exchange (A* obj, T val) noexcept;
template <class T> T atomic_store_explicit (volatile atomic<T>* obj, T val, memory_order sync) noexcept;
template <class T> T atomic_store_explicit (atomic<T>* obj, T val, memory_order sync) noexcept;
T atomic_store_explicit (volatile A* obj, T val, memory_order sync) noexcept;
T atomic_store_explicit (A* obj, T val, memory_order sync) noexcept;
template <class T> bool atomic_compare_exchange_weak (volatile atomic<T>* obj, T* expected, T val) noexcept;
template <class T> bool atomic_compare_exchange_weak (atomic<T>* obj, T* expected, T val) noexcept;
bool atomic_compare_exchange_weak (volatile A* obj, T* expected, T val) noexcept;
bool atomic_compare_exchange_weak (A* obj, T* expected, T val) noexcept;
template <class T> bool atomic_compare_exchange_weak_explicit (volatile atomic<T>* obj,T* expected, T val, memory_order success, memory_order failure) noexcept;
template <class T> bool atomic_compare_exchange_weak_explicit (atomic<T>* obj,T* expected, T val, memory_order success, memory_order failure) noexcept;
bool atomic_compare_exchange_weak_explicit (volatile A* obj,T* expected, T val, memory_order success, memory_order failure) noexcept;
bool atomic_compare_exchange_weak_explicit (A* obj, T* expected, T val, memory_order success, memory_order failure) noexcept;
template <class T> bool atomic_compare_exchange_strong (volatile atomic<T>* obj, T* expected, T val) noexcept;
template <class T> bool atomic_compare_exchange_strong (atomic<T>* obj, T* expected, T val) noexcept;
bool atomic_compare_exchange_strong (volatile A* obj, T* expected, T val) noexcept;
bool atomic_compare_exchange_strong (A* obj, T* expected, T val) noexcept;
template <class T> bool atomic_compare_exchange_strong_explicit (volatile atomic<T>* obj, T* expected, T val, memory_order success, memory_order failure) noexcept;
template <class T> bool atomic_compare_exchange_strong_explicit (atomic<T>* obj, T* expected, T val, memory_order success, memory_order failure) noexcept;
bool atomic_compare_exchange_strong_explicit (volatile A* obj, T* expected, T val, memory_order success, memory_order failure) noexcept;
bool atomic_compare_exchange_strong_explicit (A* obj, T* expected, T val, memory_order success, memory_order failure) noexcept;
template <class T> T atomic_fetch_add (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_fetch_add (atomic<T>* obj, T val) noexcept;
template <class U> U* atomic_fetch_add (volatile atomic<U*>* obj, ptrdiff_t val) noexcept;
template <class U> U* atomic_fetch_add (atomic<U*>* obj, ptrdiff_t val) noexcept;
T atomic_fetch_add (volatile A* obj, M val) noexcept;
T atomic_fetch_add (A* obj, M val) noexcept;
template <class T> T atomic_fetch_add_explicit (volatile atomic<T>* obj, T val, memory_order sync) noexcept;
template <class T> T atomic_fetch_add_explicit (atomic<T>* obj, T val, memory_order sync) noexcept;
template <class U> U* atomic_fetch_add_explicit (volatile atomic<U*>* obj, ptrdiff_t val, memory_order sync) noexcept;
template <class U> U* atomic_fetch_add_explicit (atomic<U*>* obj, ptrdiff_t val, memory_order sync) noexcept;
T atomic_fetch_add_explicit (volatile A* obj, M val, memory_order sync) noexcept;
T atomic_fetch_add_explicit (A* obj, M val, memory_order sync) noexcept;
template <class T> T atomic_fetch_sub (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_fetch_sub (atomic<T>* obj, T val) noexcept;
template <class U> U* atomic_fetch_sub (volatile atomic<U*>* obj, ptrdiff_t val) noexcept;
template <class U> U* atomic_fetch_sub (atomic<U*>* obj, ptrdiff_t val) noexcept;
T atomic_fetch_sub (volatile A* obj, M val) noexcept;
T atomic_fetch_sub (A* obj, M val) noexcept;
template <class T> T atomic_fetch_sub_explicit (volatile atomic<T>* obj, T val, memory_order sync) noexcept;
template <class T> T atomic_fetch_sub_explicit (atomic<T>* obj, T val, memory_order sync) noexcept;
template <class U> U* atomic_fetch_sub_explicit (volatile atomic<U*>* obj, ptrdiff_t val, memory_order sync) noexcept;
template <class U> U* atomic_fetch_sub_explicit (atomic<U*>* obj, ptrdiff_t val, memory_order sync) noexcept;
T atomic_fetch_sub_explicit (volatile A* obj, M val, memory_order sync) noexcept;
T atomic_fetch_sub_explicit (A* obj, M val, memory_order sync) noexcept;
template <class T> T atomic_fetch_and (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_fetch_and (atomic<T>* obj, T val) noexcept;
T atomic_fetch_and (volatile A* obj, T val) noexcept;
T atomic_fetch_and (A* obj, T val) noexcept;
template <class T> T atomic_fetch_and_explicit (volatile atomic<T>* obj, T val, memory_order sync) noexcept;
template <class T> T atomic_fetch_and_explicit (atomic<T>* obj, T val, memory_order sync) noexcept;
T atomic_fetch_and_explicit (volatile A* obj, T val, memory_order sync) noexcept;
T atomic_fetch_and_explicit (A* obj, T val, memory_order sync) noexcept;
template <class T> T atomic_fetch_or (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_fetch_or (atomic<T>* obj, T val) noexcept;
T atomic_fetch_or (volatile A* obj, T val) noexcept;
T atomic_fetch_or (A* obj, T val) noexcept;
template <class T> T atomic_fetch_or_explicit (volatile atomic<T>* obj, T val, memory_order sync) noexcept;
template <class T> T atomic_fetch_or_explicit (atomic<T>* obj, T val, memory_order sync) noexcept;
T atomic_fetch_or_explicit (volatile A* obj, T val, memory_order sync) noexcept;
T atomic_fetch_or_explicit (A* obj, T val, memory_order sync) noexcept;
template <class T> T atomic_fetch_xor (volatile atomic<T>* obj, T val) noexcept;
template <class T> T atomic_fetch_xor (atomic<T>* obj, T val) noexcept;
T atomic_fetch_xor (volatile A* obj, T val) noexcept;
T atomic_fetch_xor (A* obj, T val) noexcept;
template <class T> T atomic_fetch_xor_explicit (volatile atomic<T>* obj, T val, memory_order sync) noexcept;
template <class T> T atomic_fetch_xor_explicit (atomic<T>* obj, T val, memory_order sync) noexcept;
T atomic_fetch_xor_explicit (volatile A* obj, T val, memory_order sync) noexcept;
T atomic_fetch_xor_explicit (A* obj, T val, memory_order sync) noexcept;
与原子对象初始化相关的宏:
- ATOMIC_VAR_INIT(val):初始化 std::atomic 對象.
- ATOMIC_FLAG_INIT:初始化 std::atomic_flag 對象.
李白的blog
256code