5.3.6 原子操作对非原子的操作排序

当你使用一个普通的非原子bool类型来替换清单5.12中的x(就如同你下面看到的代码),行为 和替换前完全一样。

清单5.13 使用非原子操作执行序列

#include <atomic>
#include <thread>
#include <assert.h>bool x = false;          // x现在是一个非原子变量std::atomic<bool> y;std::atomic<int> z;void write_x_then_y()
{x = true;  // 1 在栅栏前存储std::atomic_thread_fence(std::memory_order_release);y.store(true, std::memory_order_relaxed);  // 2 在栅栏后存储y
}  void read_y_then_x()
{while(!y.load(std::memory_order_relaxed)); // 3 在#2写入前,持续等待std::atomic_thread_fence(std::memory_order_acquire);if(x) { // 4 这里读取到的值,是#1中写入++z;}
}int main()
{x = false;y = false;z = 0;std::thread a(write_x_then_y);std::thread b(read_y_then_x);a.join();b.join();assert(z.load() != 0);   // 5 断言将不会触发
}

栅栏仍然为存储x①和存储y②,还有加载y③和加载x④提供一个执行序列,并且这里仍然有一 个先行关系,在存储x和加载x之间,所以断言⑤不会被触发。②中的存储和③中对y的加载, 都必须是原子操作;否则,将会在y上产生条件竞争,不过一旦读取线程看到存储到y的操 作,栅栏将会对x执行有序的操作。这个执行顺序意味着,x上不存在条件竞争,即使它被另 外的线程修改或被其他线程读取。

不仅是栅栏可对非原子操作排序。你在清单5.10中看到 memory_order_release/memory_order_consume对,也可以用来排序非原子访问,为的是可 以动态分配对象,并且本章中的许多例子都可以使用普通的非原子操作,去替代标记为 memory_order_relaxed的操作。

对非原子操作的排序,可以通过使用原子操作进行,这里“前序”作为“先行”的一部分,就显得 十分重要了。如果一个非原子操作是“序前”于一个原子操作,并且这个原子操作需要“先行”与 另一个线程的一个操作,那么这个非原子操作也就“先行”于在另外线程的那个操作了。 这一序列操作,就是在清单5.13中对x的操作,并且这也就是清单5.2能工作的原因。对于C++标准 库的高阶同步工具来说,这些都是基本,例如互斥量和条件变量。可以回看它们都是如何工 作的,可以对清单5.1中简单的自旋锁展开更加深入的思考。

使用 std::memory_order_acquire 序列的lock()操作是在flag.test_and_set()上的一个循环,并且 使用 std::memory_order_release 序列的unlock()调用flag.clear()。当第一个线程调用lock()时, 标志最初是没有的,所以第一次调用test_and_set()将会设置标志,并且返回false,表示线程 现在已锁,并且结束循环。之后,线程可以自由的修改由互斥量保护的数据。这时,任何想 要调用lock()的线程,将会看到已设置的标志,而后会被test_and_set()中的循环所阻塞。

当线程带锁线程完成对保护数据的修改,它会调用unlock(),相当于调用带有 std::memory_order_release 语义的flag.clear()。这与随后其他线程访问flag.test_and_set() 时调用lock()同步(见5.3.1节),这是因为对lock()的调用带有 std::memory_order_acquire 语义。 因为对于保护数据的修改,必须先于unlock()的调用,所以修改“先行”于unlock(),并且还“先 行”于之后第二个线程对lock()的调用(因为同步关系是在unlock()和lock()中产生的),还“先 行”于当第二个线程获取锁后,对保护数据的任何访问。

虽然,其他互斥量的内部实现不尽相同,不过基本原理都是一样的:在某一内存位置上,lock() 作为一个获取操作存在,在同样的位置上unlock()作为一个释放操作存在。

5.3.6 原子操作对非原子的操作排序相关推荐

  1. 原子和非原子oc_原子宝藏

    原子和非原子oc by Dennis Bruijn / @0x1ad2 通过丹尼斯·布鲁恩/ @ 0x1ad2 原子宝藏 (Atom treasures) 我不能没有的Atom插件列表 (a list ...

  2. [非原子批处理出现故障]使用 getNextException() 来检索已经过批处理的特定元素的异常。 ERRORCODE=-4228, SQLSTATE=null

    [jcc][t4][102][10040][3.57.82] 非原子批处理出现故障.虽然已经提交了批处理,但是该批处理的某个成员至少发生了一个异常. 使用 getNextException() 来检索 ...

  3. C++内存模型和原子类型操作

    C++内存模型和原子类型操作 std::memory_order初探 动态内存模型可以理解为存储一致性模型,主要是从行为上来看多个线程对同一个对象读写操作时所做的约束,动态内存理解起来会有少许复杂,涉 ...

  4. 基础才是重中之重~何为原子化操作

    占占定义: 原子化操作,操作原子化,这在软件开发中经常被听到,那到底什么是操作原子化呢,其实从字面上不难理解,原子化就是一体化,整体化,原子化操作就是将多个操作组合在一起,要么这个组合一起发生,要么一 ...

  5. linux 原子整数操作详解 及 volatile (二)

    2019独角兽企业重金招聘Python工程师标准>>> 原子操作,顾名思义,就是说像原子一样不可再细分不可被中途打断.一个操作是原子操作,意思就是说这个操作是以原子的方式被执行,要一 ...

  6. 第5章 C++内存模型和原子类型操作

    第5章 C++内存模型和原子类型操作 本章主要内容 ※ C++11内存模型详解 ※ 标准库提供的原子类型 使用各种原子类型 ※ 原子操作实现线程同步功能 C++11标准中,有一个十分重要特性,常被程序 ...

  7. boost::mpi模块非阻塞点对点操作的测试

    boost::mpi模块非阻塞点对点操作的测试 实现功能 C++实现代码 实现功能 boost::mpi模块非阻塞点对点操作的测试 C++实现代码 #include <boost/mpi/non ...

  8. 给定一个数组,求如果排序之后,相邻两数的最大差值,要求时间复杂度O(N),且要求不能用非基于比较的排序。

    给定一个数组,求如果排序之后,相邻两数的最大差值,要求时间复杂度O(N),且要求不能用非基于比较的排序. import java.util.Arrays;public class MaximumDif ...

  9. 合并排序 非递归 java_合并排序-非递归

    #include //合并排序非递归--自然合并排序 typedef int Type; using namespace std; void Merge(Type c[],Type d[],int l ...

最新文章

  1. 简简单单搞掂恼人的Laravel 5安装
  2. 2015年度个人总结和计划
  3. 如何编写高性能的C#代码(二)
  4. json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
  5. RMAN 还原与恢复
  6. uploadify.js
  7. 微服务升级_SpringCloud Alibaba工作笔记0007---spring gateway搭建
  8. backbone学习笔记:集合(Collection)
  9. 博文视点大讲堂第36期——让Oracle跑得更快(3大oracle ACE联合推荐)
  10. 一次JDBC与MySQL因“CST”时区协商误解导致时间差了13或14个小时
  11. 全国省份城市区域代码
  12. xp系统的无线配置服务器,Windows XP系统下无线网卡配置及安装
  13. 前端面试题总汇、常考、笔试题等
  14. zmap扫描mysql_基于zmap 的应用层扫描器 zgrab (一)
  15. 淘宝镜像安装以及配置
  16. linux系统安装驱动rtl8188eu,rtl8188eu_USB_linux RTL8188EU驱动源码
  17. Java学习笔记-IO
  18. Prince and Princess问题解决
  19. SpringCloud疑难杂症
  20. 飞机机翼的构造及其原理

热门文章

  1. Java解决找不到主类或者无法加载主类
  2. Google七项不得不知的搜索技巧
  3. Redis RDB和AOF总结
  4. redis的info
  5. 《Xcode实战开发》——1.1节下载
  6. python 通信中间件_Python Web框架Sanic middleware – 中间件
  7. 计算机会计内容是什么,会计电算化的主要内容是什么?
  8. Delphi 的运算符列表
  9. ROS Nodelet使用
  10. Android 使用Nginx rtmp 模块