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