Khan's Notebook GCC/GNU/Linux Delphi/Window Java/Anywhere

路漫漫,长修远,我们不能没有钱
随笔 - 172, 文章 - 0, 评论 - 257, 引用 - 0
数据加载中……

C++ Atomic

C++ Atomic

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

内存序模型 是讨论在 原子操作 附近的 读写 操作顺序

// c++11  ~~  c++17
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;
//c++20
enum class memory_order : /*unspecified*/ {
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类型

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 状态.

成员函数

//返回该std::atomic_flag对象当前状态,如果当前状态为false则设置(set) 该对象为true. 该函数是原子的
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;
//清除std::atomic_flag 对象的标志位, 即设置atomic_flag 的值为false
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;  }

基于std::atom_flag类的C风格API

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 比 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 代表了如下类型 charsigned charunsigned charshortunsigned shortintunsigned intlongunsigned longlong longunsigned long longchar16_tchar32_twchar_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++(intvolatile//后缀++     integral operator++(int);
    integral 
operator--(intvolatile//后缀--     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++(intvolatile;     T* operator++(int);
    T
* operator--(intvolatile;     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; }

基于std::atomic 类模板的C风格API

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;
//初始化原子對象. 如果對一個已初始化的原子對象再次調用 atomic_init(), 則會導致未定義行為(undefined behavior)
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

posted on 2022-10-14 16:36 Khan 阅读(174) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理