zoukankan      html  css  js  c++  java
  • atomic用法

    memory order

    源码变成可执行程序,一般由预编译,编译,汇编,链接。源码重排序一般分为编译期重排序和运行期重排序。

    编译期重排序:编译器在不改变单线程程序的语义的前提下,可以重新安排语句的执行顺序。在不改变程序的语义的前提下,尽可能减少寄存器的读取,存储次数,充分复用寄存器的存储值。

    CPU乱序执行

    名称 语义               
    memory_order_relaxed Relaxed语义
    memory_order_consume Release-Acquire语义
    memory_order_acquire Release-Acquire语义
    memory_order_release  Release-Acquire语义
    memory_order_acq_rel  Release-Acquire语义
    memory_order_seq_cst  Sequential consistency语义

     

     

     

     

     

     

     

    synchronizes-with、happens-before关系

    synchronizes-with: 如果线程A存储一个值,而线程B读取该值,那么线程A中的存储和线程B的载入之间存在一种synchronizes-with关系

    happens-before: 如果一个操作排在另外一个操作之前,那么该操作就该发生于另一个操作之前

    Relaxed语义

    最宽松的内存操作约定,不会保证修改会不会及时被其他的线程看到,也不对乱序做任何要求

    relaxed的原子类型操作不参与synchronizes-with关系。

    不同变量的relaxed可以被自由的重排,前提它们服从所有约束下的happens-before关系

    #include <atomic>
    #include <thread>
    #include <assert.h>
    
    atomic<bool> x, y;
    atomic<int> z;
    
    void write_x_then_y() 
    {
         x.store(true, memory_order_relaxed);  
         y.store(true, memory_order_relaxed);
    }
    
    void read_y_then_x()
    {
         while (!y.load(memory_order_relaxed));
         if (x.load(memory_order_relaxed)) 
              ++z;
    }int main()
    {
         x = false;
         y = false;
         z = 0;
         thread a(write_x_then_y);
         thread b(read_y_then_x);
         a.join();
         b.join();
         assert(z.load() != 0); // z可能等于0
    }

    Release-Acquire语义Sequential consistency语义

      release和acquire总是一起使用

      release用于写操作,acquire用于读操作

      release之前的写操作不允许乱序到release之后, acquire之前的读操作不允许乱序到acquire之前

      acquire的修改会及时被release看到

    Sequential consistency语义

      sequential consistency 相当于 release + acquire 之外,还加上了一个对该操作加上全局顺序的要求

    #include <atomic>
    #include <thread>
    #include <assert.h>
    
    atomic<bool> x, y;
    atomic<int> z;
    
    void write_x() 
    {
         x.store(true, memory_order_seq_cst);  
    }
    
    void write_y()
    {
         y.store(true, memory_order_seq_cst);
    }
    
    void read_x_then_y()
    {
         while (!x.load(memory_order_seq_cst));
         if (y.load(memory_order_seq_cst)) 
              ++z;
    }
    
    void read_y_then_x()
    {
         while(!y.load(memory_order_seq_cst));
         if (x.load(memory_order_seq_cst))
              ++z;
    }
    
    int main()
    {
         x = false;
         y = false;
         z = 0;
         thread a(write_x);
         thread b(write_y);
         thread c(read_x_then_y);
         thread d(read_y_then_x);
         a.join();
         b.join();
         c.join();
         d.join();
         assert(z.load() != 0); // z不可能等于0
    }

     

    store,load

    atomic<bool> x, y;  
    atomic<int> z;
    
    void write()
    {
        x.store(true, memory_order_relaxed);
        y.store(true, memory_order_release); // x的值比y先填充值
    }
    
    
    void read()
    {
        while(!y.load(memory_order_acquire)); // y在等write值得填充
        if (x.load(memory_order_relaxed)) {
            z++;
        }
    }
    
    int main()
    {
        x = false;
        y = false;
        z = 0;
    
        thread t1(write);
        thread t2(read);
        t1.join();
        t2.join();
    
        cout << "z: " << z << endl;
    }

     

    exchage

    compare_exchange_weak

    bool compare_exchange_weak(T& expected, T val, memory_order sync = memory_order_seq_cst) 

    NOTE:

    1. atomic变量的值与expected进行比较, 如果结果true, 用val更新atomic的值(like store); 如果结果为false, 用atomic的值更新expected的值.

    2. 这个函数能获得这个atomic变量的值,并且如果比较的结果是true的话就修改这个值. 整个操作是原子操作,在读取或者修改这个值得瞬间,其他的线程不会修改这个值.

    3. memory_order 是否生效也是根据比较的结果,如果结果为true,那么生效,否则不生效

    4. compare_exchage_weak允许伪失败(fail spuriously),尽管expected值确实和atomic变量的值相等,仍然会返回false; 这需要使用while操作

    #include <iostream>
    #include <atomic>
    #include <thread>
    #include <vector>
    using namespace std;
    
    struct Node {
        int value;
        Node *next;
    };
    
    atomic<Node*> list_head(nullptr);
    void Append(int val)
    {
        Node *p_old_node = list_head;
        Node *p_new_node = new Node {val, p_old_node};
    
        while (!list_head.compare_exchange_weak(p_old_node, p_new_node)) {
            p_new_node->next = p_old_node;
        }
    }
    
    int main()
    {
        vector<thread> threads;
        for (int i = 0; i < 10; i++) {
            threads.push_back(thread(Append, i));
        }
    
        for (auto &i : threads) {
            i.join();
        }
    
        for (Node *it = list_head; it != nullptr; it = it->next) {
            cout << it->value << " ";
        }
        cout << endl;
    }

     

    compare_exchange_strong

    bool compare_exchange_strong (T& expected, T val, memory_order sync = memory_order_seq_cst)

    1. compare_exchange_strong的用法和compare_exchange_weak基本用法都一样

    2. compare_exchange_strong不允许伪失败(fail spuriously)

    3. compare_exchange_weak的循环结构在某些机器上可能有更好的性能

    atomic<int> ai;
    int tst_val = 4;
    int new_val = 5;
    bool exchanged = false;
    
    void valsout()
    {
        cout << "ai: " << ai << " tst_val: " << tst_val << " new_val: " << new_val << " exchanged: " << boolalpha << exchanged << endl;
    }
    
    
    int main()
    {
        ai = 3;
        valsout(); //ai = 3, tst_val = 4, new_val = 5, exchanged = false;
    
        exchanged = ai.compare_exchange_strong(tst_val, new_val);
        valsout();  //ai = 3, tst_val = 3, new_val = 5, exchanged = false;
    
        exchanged = ai.compare_exchange_strong(tst_val, new_val);
        valsout();  //ai = 3, tst_val = 3, new_val = 5, exchanged = false;
    }

     

     

    参考资料:

    [1] http://www.cplusplus.com/reference/atomic/atomic/

    [2] <<c++并发编程>>

    [3] http://www.cnblogs.com/haippy/p/3252056.html

    [4] http://www.cnblogs.com/muhe221/articles/5049474.html

  • 相关阅读:
    51Nod1740 蜂巢迷宫
    51Nod1279 扔盘子
    51Nod1095 Anigram单词
    51Nod1094 和为k的连续区间
    51Nod1072 威佐夫游戏
    PHP 图片处理
    ubuntu 安装 ftp
    linux下ab网站压力测试命令
    iptables FOr linux
    discuz 个性化时间函数
  • 原文地址:https://www.cnblogs.com/457220157-FTD/p/5306676.html
Copyright © 2011-2022 走看看