走进C++11(四十一)释放获得顺序 内存模型(四)

关注公众号获取更多信息:

若线程 A 中的一个原子存储带标签 memory_order_release ,而线程 B 中来自同一变量的原子加载带标签 memory_order_acquire ,则从线程 A 的视角先发生于原子存储的所有内存写入(非原子及宽松原子的),在线程 B 中成为可见副效应,即一旦原子加载完成,则保证线程 B 能观察到线程 A 写入内存的所有内容。

 

同步仅建立在释放获得同一原子对象的线程之间。其他线程可能看到与被同步线程的一者或两者相异的内存访问顺序。

 

在强顺序系统( x86 、 SPARC TSO 、 IBM 主框架)上,释放获得顺序对于多数操作是自动进行的。无需为此同步模式添加额外的 CPU 指令,只有某些编译器优化受影响(例如,编译器被禁止将非原子存储移到原子存储-释放后,或将非原子加载移到原子加载-获得前)。在弱顺序系统( ARM 、 Itanium 、 Power PC )上,必须使用特别的 CPU 加载或内存栅栏指令。

 

互斥锁(例如 std::mutex 或原子自旋锁)是释放获得同步的例子:线程 A 释放锁而线程 B 获得它时,发生于线程 A 环境的临界区(释放之前)中的所有事件,必须对于执行同一临界区的线程 B (获得之后)可见。

 

#include <thread>#include <atomic>#include <cassert>#include <string> std::atomic<std::string*> ptr;int data; void producer(){    std::string* p  = new std::string("Hello");    data = 42;    ptr.store(p, std::memory_order_release);} void consumer(){    std::string* p2;    while (!(p2 = ptr.load(std::memory_order_acquire)))        ;    assert(*p2 == "Hello"); // 绝无问题    assert(data == 42); // 绝无问题} int main(){    std::thread t1(producer);    std::thread t2(consumer);    t1.join(); t2.join();}

 

下例演示三个线程间传递性的释放获得顺序

 

#include <thread>#include <atomic>#include <cassert>#include <vector> std::vector<int> data;std::atomic<int> flag = {0}; void thread_1(){    data.push_back(42);    flag.store(1, std::memory_order_release);} void thread_2(){    int expected=1;    while (!flag.compare_exchange_strong(expected, 2, std::memory_order_acq_rel)) {        expected = 1;    }} void thread_3(){    while (flag.load(std::memory_order_acquire) < 2)        ;    assert(data.at(0) == 42); // 决不出错} int main(){    std::thread a(thread_1);    std::thread b(thread_2);    std::thread c(thread_3);    a.join(); b.join(); c.join();}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值