5.3 同步操作和强制排序

假设你有两个线程,一个向数据结构中填充数据,另一个读取数据结构中的数据。为了避免恶性条件竞争,第一个线程设置一个标志,用来表明数据已经准备就绪,并且第二个线程在这个标志设置前不能读取数据。下面的程序清单就是这样的情况。

清单5.2 不同线程对数据的读写

#include <vector>
#include <atomic>
#include <iostream>
#include <chrono>
#include <thread>std::vector<int> data;
std::atomic_bool data_ready(false);void reader_thread()
{while(!data_ready.load())  {   // 1std::this_thread::sleep_for(std::chrono::milliseconds(1));}std::cout << "The answer = " << data[0] << "\n"; // 2
}void writer_thread()
{data.push_back(42);    // 3data_ready = true; // 4
}

先把等待数据的低效循环①放在一边(你需要这个循环,否则想要在线程间共享数据就是不切实际的:数据的每一项都必须是原子的)。你已经知道,当非原子读②和写③对同一数据结构进行无序访问时,将会导致未定义行为的发生,因此这个循环就是确保访问循序被严格的遵守的。

强制访问顺序是由对std::atomic<bool>类型的data_ready变量进行操作完成的;这些操作通过“先行发生”(happens-before)和“同步发生”(synchronizes-with)确定必要的顺序。写入数据③的操作,在写入data_ready标志④的操作前发生,并且读取标志①发生在读取数据②之前。当data_ready①为true,写操作就会与读操作同步,建立一个“先行发生”关系。因为“先行发生”是可传递的,所以写入数据③先行于写入标志④,这两个行为又先行于读取标志的操作①,之前的操作都先行与读取数据②,这样你就拥有了强制顺序:写入数据先行与读取数据, 其他没问题了。图5.2展示了先行发生在两线程间的重要性。我向读者线程的while循环中添加 了一对迭代。

图5.2 对非原子操作,使用原子操作对操作进行强制排序

所有事情看起来非常直观:对一个值来说,写操作必然先于读操作!在默认它们都是原子操作的时候,这无疑是正确的(这就是原子操作为默认属性的原因),不过这里需要详细说明:原子操作对于排序要求,也有其他的选项,会在稍后进行详述。

现在,你已经了解了“先行发生”和“同步发生”操作,也是时候看看他们真正的意义了。我将从“同步发生”开始说起。

5.3.1 同步发生

5.3 同步操作和强制排序相关推荐

  1. Hive窗口函数Over和排序函数Rank

    - 目录 1.聚合函数+over 2.partition by子句 3.order by子句 4.★window子句(里面包含) - PRECEDING:往前 - FOLLOWING:往后 - CUR ...

  2. sorttable.js:让你的所有HTML表格都可以排序

    虽然网页设计社区逐渐不再使用表格来布置页面结构,但表格确实有一个至关重要的用途,它们的原始用途.它们用于布置表格数据.例如,想象一张员工表. Name 薪水 延期 开始日期 开始日期(美国) 博客,弗 ...

  3. 如何让C#的PropertyGrid的Category按照类的定义顺序进行排序?

    默认情况C#会在PropertyGrid中按照Alphabetical的规则对Category进行排序 public class Person {[Category("Score" ...

  4. SparkShuffle机制 - ⽀持⾼效聚合和排序的数据结构

    . 一 .前言 二 .AppendOnlyMap的原理 三 .ExternalAppendOnlyMap 3.1. 如何获知当前AppendOnlyMap的⼤⼩?因为AppendOnlyMap中不断添 ...

  5. elasticsearch查询结果排序

    相关性排序 默认情况下,结果集会按照相关性进行排序,相关性越高,排名越靠前.在Elasticsearch中相关性分值会用_score字段来给出一个浮点型的数值,所以默认情况下,结果集是以_score倒 ...

  6. 5.2.7 原子操作的释放函数

    5.2.7 原子操作的释放函数 直到现在,我都还没有去描述成员函数对原子类型操作的形式.但是,在不同的原子类型中 也有等价的非成员函数存在.大多数非成员函数的命名与对应成员函数有关,但是需 要&quo ...

  7. C++`中的原子操作和原子类型

    5.2 C++中的原子操作和原子类型 原子操作 是个不可分割的操作. 在系统的所有线程中,你是不可能观察到原子操作完成了一半这种情况的: 它要么就是做了,要么就是没做,只有这两种可能. 如果从对象读取 ...

  8. linux内核RCU

    RCU背景 RCU在2002年中增加到内核中的,是一种基于互斥的同步机制,当读多写少并且读性能要求较高时候能够达到最大的效果,它总体上属于一种空间换时间的方式,用短时间内占用额外的内存来保证快速的访问 ...

  9. c++ 原子操作 赋值_5.2 C++中的原子操作和原子类型

    5.2 C++中的原子操作和原子类型 原子操作 是个不可分割的操作. 在系统的所有线程中,你是不可能观察到原子操作完成了一半这种情况的: 它要么就是做了,要么就是没做,只有这两种可能. 如果从对象读取 ...

最新文章

  1. go context之WithCancel的使用
  2. Redis在PHP项目中的应用
  3. C# Winform 窗体美化(目录)
  4. 抓住那头牛(信息学奥赛一本通-T1253)
  5. 大橙子_【大橙子活动】工程学院新媒体中心第二届总结大会圆满结束!
  6. CentOS 6.5 + Nginx 1.8.0 + PHP 5.6(with PHP-FPM) 负载均衡源码安装 之 (三)Nginx负载均衡配置...
  7. 10.RabbitMQ实战 --- 监控
  8. sublime编辑器修改默认的Tab缩进风格
  9. Qt制作贪吃蛇小游戏
  10. R语言数据分析笔记——方差分析(单因素方差分析、双因素方差分析、多因素方差分析)在Excel、SPSS、R语言中的操作)
  11. XRD分析软件安装及使用
  12. 绕过微信客户端授权,获取网页源码
  13. java调用手机截屏_android实现手机截屏并保存截图功能
  14. iis搭建ftp服务器及身份验证设置
  15. GD32VF103_CAN发送
  16. 2022年亚太地区大学生数学建模竞赛/2022年亚太杯ABCD题思路
  17. 青龙面板快手极速版教程第二弹
  18. DCA1000雷达数据采集卡的快速使用(TI xWR1xxx系列雷达)
  19. Fiddler使用 抓取手机数据包及中文乱码解决方案
  20. 原理图端口符号_接线图和原理图有什么区别?

热门文章

  1. Property 'filter' does not exist on type 'Observable' 报错解决方法
  2. yii2 提供接口给java_Yii2 基于RESTful架构的 advanced版API接口开发 配置、实现、测试 (转)...
  3. win10+linux系统进入安全模式,Win10进入安全模式的方法
  4. i java 字节码_用java字节码解释i++和++i
  5. 基于jQuery的uploadify(flash上传文件)控件v1.6.2 bug修正
  6. Android基础 写给新手的Android环境配置
  7. IOS调试—断点调试以及动态输出
  8. centos7以上系统服务管理命令-systemctl
  9. root用户重置其他密码
  10. 时序分析基本概念介绍——SDC概述