atomic 原子操作
1. 什么樣的type 可以轉(zhuǎn)化成atomic?
任何 trivially copyable 的數(shù)據(jù)可以被轉(zhuǎn)換成atomic.
#include <iostream> #include <type_traits>struct A {int m; };struct B {B(B const&) {} };struct C {virtual void foo(); };struct D {int m;D(D const&) = default; // -> trivially copyableD(int x): m(x+1) {} };int main() {std::cout << std::boolalpha;std::cout << std::is_trivially_copyable<A>::value << '\n';std::cout << std::is_trivially_copyable<B>::value << '\n';std::cout << std::is_trivially_copyable<C>::value << '\n';std::cout << std::is_trivially_copyable<D>::value << '\n'; }Output:
true false false truetrivally copyable 需要滿足3個條件:
2.atomic 支持哪些操作
std::atomic<int> x(0);++x; // Atomic pre-increment x++; // Atomic post-increment x +=1; // Atomic increment x|=1; // Atomic bit set x *=2; // 錯誤的寫法,不支持乘法,編譯器不通過 int y = x+1; // Atomic Read x x = y+1; // Atomic write x x = x+1; // Atomic Read followed by atomic write! x = x*2; // Atomic read followed by atomic write !其中x = x+1; 和 x = x*2; 有兩個原子的操作,在多線程里面會被解釋成兩條執(zhí)行的指令。
例如:
輸出:
final result:19982
其他的操作:
std::atomic<T> x;T y = x.load(); // 等價于 T y=x; x.store(y); //等價于 x =y;// 2. atomic exchange T z = x.exchange(y); // 等于 T z = x; x=y;// 3. compare and swap(condition exchange) T y ;bool succ = x.compare_exchange_strong(y, z); //. 如果 x ==y , 那么 x =z; 并且返回true, 如果 x!=y, 那 y=z; 返回falsecompare and swap (CAS)有什么特殊的地方嗎?
CAS 被用在lock-free的程序里面,一個例子:
使用CAS可以寫出lock-free的代碼,具體參考:https://zhuanlan.zhihu.com/p/53012280
兩種操作:compare_exchange_strong 和 compare_exchange_weak
x.compare_exchange_strong(old_x, new_x)
x.compare_exchange_weak(old_x, new_x)
compare_exchange_strong和compare_exchange_weak的區(qū)別是,如果一些事情導(dǎo)致compare_exchange_weak失敗,即使對于x==old_x.
3. Atomic 的效率
atomic 操作會互相等待嗎?
結(jié)論是atomic 會互相等待。
特別對于寫的操作會互相等待
對于讀的操作可以更好的效率
4. Atomic queue、List
int q[N]; std::atomic<size_t> front; void push(int x) {size_t my_slot = front.fetch_add(1); // atomicq[my_slot] = x; // exclusive slot }atomic 可以作為非atomic memory 的index。
atomic list
struct Node {int x;Node* next; };std::atomic<Node*> head; void push_front(int x) {Node* new_node = new Node;new_node->x =x;Node* old_node = head;while (head.compare_exchange_strong(old_node, new_node)) {new_node->next = old_node;} }atomic 變量是一個指針指向非atomic的內(nèi)存。
5. Memory barriers
atomics 另一個比較重要的概念是Memory barriers.
Memory barriers也就是一個cpu核心造成的內(nèi)存的改變變成其他核心cpu可見。
- 如果不指定內(nèi)存的順序,異步讀取數(shù)據(jù)幾乎是不可能的
- Memory barriers是全局的控制,對于所有的cpu核心生效
- Memory barriers是通過硬件實現(xiàn)的
- barriers一般是在讀或者寫的時候指定
c++11 支持標(biāo)準(zhǔn)的Memory barriers。
std::atomic<int> a(12); a.load(std::memory_order_release)- std::memory_order_relaxed
沒有Memory barriers
- std::memory_order_acquire
Acquire barrier保證所有的在barrier之后的程序內(nèi)存操作是可見的。
讀或者寫不會被reordered 到barrier的后面。
- std::memory_order_release
release Barrier 保證所有的在barrier之前的內(nèi)存操作,在barrier是可見的,之后的操作不回被reorder 到barrier之前。
例如barrier之后的寫內(nèi)存的操作不會reordered到barrier之前。 - std::memory_order_acq_rel
acquire 和release barriers一般都是一起使用。
線程1 寫atomic variable x 通過acquire barrier。
線程2 讀atomic variable x 通過release barrier。
發(fā)生在線程1在barrier之前的所有的內(nèi)存寫的操作(在代碼order)是對于在barrier 之后的線程2是可以見的。
線程1準(zhǔn)備數(shù)據(jù)(一寫操作)然后通過更新atomic variable x. releases(publishes) 寫的結(jié)果.
線程2 acquire atomic variable x 保證數(shù)據(jù)是可見的。 - std::memory_order_acq_rel
通過將acquire 和 release 綁定起來,保證所有的操作不能穿越barrier.
僅僅當(dāng)兩個線程有相同的atomic variable. - std::memory_order_seq_cst
最嚴(yán)格的內(nèi)存序列, 原子變量單一總的修改順序。最好不要用memory_order_seq_cst 這個是嚴(yán)重影響程序的性能的。
原子操作默認(rèn)的是最嚴(yán)格的memory_order_seq_cst。不能reorder操作的順序。
Memory barriers是非常影響性能的。
總結(jié)
以上是生活随笔為你收集整理的atomic 原子操作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个漏洞潜伏54年?谁才是“潜伏界”最强
- 下一篇: grub4dos linux live,