atomic用法

memory order

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

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

CPU乱序执行

 

名称语义               
memory_order_relaxedRelaxed语义
memory_order_consumeRelease-Acquire语义
memory_order_acquireRelease-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

转载于:https://www.cnblogs.com/457220157-FTD/p/5306676.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值