日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

atomic 原子操作

發布時間:2023/12/16 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 atomic 原子操作 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 什么樣的type 可以轉化成atomic?

任何 trivially copyable 的數據可以被轉換成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 true

trivally copyable 需要滿足3個條件:

  • 連續的內存空間
  • 拷貝構造函數需要拷貝全部的bits (memcpy)
  • 沒有虛函數和 noexcept constructor
  • struct S{ int q=1; } std::atomic<S> s;

    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; 有兩個原子的操作,在多線程里面會被解釋成兩條執行的指令。
    例如:

    #include <stdio.h> #include <thread> #define INC_TO 1000000 // one million... #include <mutex> #include <functional> #include <atomic> #include <vector> int main() {std::vector<std::thread> ts;std::atomic<int> a(0);auto add_func = [&]() {a+=1;};int threads_num =20000;for(int i=0; i < threads_num; ++i) {ts.emplace_back(std::move(std::thread(add_func)));}for(int i=0; i < threads_num; ++i) {ts[i].join();}printf("final result:%d", a.load()); // std::atomic<int> a(1); // Not std::atomic<int> a =1;return 0; }

    輸出:
    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; 返回false

    compare and swap (CAS)有什么特殊的地方嗎?
    CAS 被用在lock-free的程序里面,一個例子:

    std::atomic<int> a(12);int x = a;while(! a.compare_exchange_strong(x, x+1)) {printf("x:%d", x);}

    使用CAS可以寫出lock-free的代碼,具體參考:zhuanlan.zhihu.com/p/53

    兩種操作: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的區別是,如果一些事情導致compare_exchange_weak失敗,即使對于x==old_x.

    bool compare_exchange_strong(T& old_v, T new_v) {T tmp = value; // atomic valueif (tmp != old_v) {old_v= tmp;return false;}Locl L; // Gte exclusive accesstmp = value; // value could have changeif (tmp != old_v) { old_v = tmp; return false;}value = new_v;return true; } bool compare_exchange_weak(T& old_v, T new_v) {T tmp = value; // atomic valueif (tmp != old_v) {old_v= tmp;return false;}TimedLock L; //Gte exclusive access or fail;if (! L.locked()) return false; // old_v is correct;tmp = value; // value could have changeif (tmp != old_v) { old_v = tmp; return false;}value = new_v;return true; }

    3. Atomic 的效率

    atomic 操作會互相等待嗎?
    結論是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的內存。

    5. Memory barriers

    atomics 另一個比較重要的概念是Memory barriers.
    Memory barriers也就是一個cpu核心造成的內存的改變變成其他核心cpu可見。

    • 如果不指定內存的順序,異步讀取數據幾乎是不可能的
    • Memory barriers是全局的控制,對于所有的cpu核心生效
    • Memory barriers是通過硬件實現的
    • barriers一般是在讀或者寫的時候指定

    c++11 支持標準的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之后的程序內存操作是可見的。
      讀或者寫不會被reordered 到barrier的后面。


    • std::memory_order_release
      release Barrier 保證所有的在barrier之前的內存操作,在barrier是可見的,之后的操作不回被reorder 到barrier之前。
      例如barrier之后的寫內存的操作不會reordered到barrier之前。
    • std::memory_order_acq_rel
      acquire 和release barriers一般都是一起使用。
      線程1 寫atomic variable x 通過acquire barrier。
      線程2 讀atomic variable x 通過release barrier。
      發生在線程1在barrier之前的所有的內存寫的操作(在代碼order)是對于在barrier 之后的線程2是可以見的。
      線程1準備數據(一寫操作)然后通過更新atomic variable x. releases(publishes) 寫的結果.
      線程2 acquire atomic variable x 保證數據是可見的。
    • std::memory_order_acq_rel
      通過將acquire 和 release 綁定起來,保證所有的操作不能穿越barrier.
      僅僅當兩個線程有相同的atomic variable.
    • std::memory_order_seq_cst
      最嚴格的內存序列, 原子變量單一總的修改順序。最好不要用memory_order_seq_cst 這個是嚴重影響程序的性能的。

    原子操作默認的是最嚴格的memory_order_seq_cst。不能reorder操作的順序。

    Memory barriers是非常影響性能的。

    總結

    以上是生活随笔為你收集整理的atomic 原子操作的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。