c++11 standardized memory model 内存模型
C++11 标准中引入了内存模型,其目的是为了解决多线程中可见性和顺序(order)。这是c++11最重要的新特征,标准忽略了平台的差异,从语义层面规定了6种内存模型来实现跨平台代码的兼容性。多线程代码因为其本身的复杂性问题,有引入死锁和race condition等一系列问题,可能造成的后果有crash和random error,非常难以debug,因为人的思维是线性的,mutiple threads的代码会交叉运行.
1、同时因为编译器优化和CPU指令集的优化,代码的顺序可能被打乱。那么在多线程环境下。我们看到的结果和我们预期的结果可能不一样。
2、另外多CPU独立Cache Line的同步问题,多核CPU通常有自己的一级缓存和二级缓存,访问缓存的数据很快。但是如果缓存没有同步到主存和其他核心的缓存,其他核心读取缓存就会读到过期的数据。
一个经典的例子如下:
bool flag =false;
int y = ;
// run at thread 1
void M1() {
y = ; //
flag= true; //
}
// run at thread 2
void M2() {
while (!flag); //1
y++; //2
}
如果不考虑reorder,thread2 中y的值肯定是43. 实际上却又两种可能的结果43和1. 为什么会出现这种情况?那就是因为指令重排了。 thread 1中step1 和step2 的顺序可以被编译器或者CPU指令重新reorder。
那么我们就需要武器防止这种reorder的发生。在C+11 之前都是用memory barrier,用于告诉编译器和CPU 哪些地方不能reorder 顺序,同时保证可见性顺序。这就是memory model引入的目前。规定6种不同的order来帮助我们写代码;以上的代码还有race condition的问题,大家看出来了,可能会导致undefined的行为。因为不是原子性的操作,多个线程可能同时操作同一块内存,同样memory model标准应该要杜绝race condition的情况。
如果我们保证不reorder,就一定可以得到正确的结果吗?答案是不能,我们还有考虑多线程之间可见性和顺序性问题。这与重排是不同的概念。
在一个core修改了一个变量,另一个core立马就能读到;或者你修改了两个变量,你要求另一个core在读到这两个变量的时候,要按照相同的顺序,比如这样的代码:
core 1:
x = 1024; flag = true;
core 2:
while (!flag) ; assert(x == 1024);
这段代码其实就假定了几件事情,对变量x的修改,要先于对flag的修改;并且在core 2中要感知到这样的顺序。
可能有同学会说,有这么复杂吗?我们平常不是直接加mutex互斥锁来保证多线程代码的正确性吗?是的,加锁mutex是通用的办法,加mutex互斥锁的目的是为了多线程之间的顺序性。线程和线程之间通过争取mutex锁,来实现代码正确的order执行顺序。mutex临界区保护的代码区不会跳出临界区的约束。只能等到获取mutex之后才能执行。mutex锁区域内的代码编译器和CPU仍然可以重排。
从可见性角度分析内存模型的order,为了描述多线程之间的代码之间的顺序关系和内存可见性关系。我们用happens before的语义表示,两行代码之间的关系。编译器和CPU的单线程内的优化是按照规则的,优化前的happens before的关系不会被打乱。这也是我们如果是单线程,就无需考虑代码重排的问题。因为编译器和CPU保证语义的正确。我们用happens before来表示我们期待的代码顺序关系。
void func(){
int i=; //1
int j=; //2
int s=i+j; //3
}
1,2 之间没有happen before联系。大家都不依赖对方,所以可以重排。但是3绝对不可能重排到1,2 之前,因为1,2 happens before 3. 这是编译器单线程优化的规则。happen before不仅仅是顺序,而是可见性。也就是1,2的结果,肯定在3之前就能被step 3感知到。
为什么要强调可见性呢?因子在单线程中,同一个内存read的结果肯定相同,但是在多线程中因为cache,是可能不相同的。那么我们在多线程中,为了表示我们期待的执行结果。我们也用happens before表示。因为执行顺序不代表可见性。
bool flag =false;
int y = ;
// run at thread 1
void M1() {
y = ; //
flag= true; //
}
// run at thread 2
void M2() {
while (!flag); //3
y++; //4 }
多线程之间我们可以认为的规定happens before语义, 如此就能保证正确的结果。那么如何保证 1,2 happens before 3呢,memory model。
既然知道多线程同步的难点,那么看看C++11提供了哪些内存模型:都是基于原子的操作
typedef enum memory_order
{
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst
} memory_order;
http://senlinzhan.github.io/2017/12/04/cpp-memory-order/
c++11 standardized memory model 内存模型的更多相关文章
- 内存模型 Memory model 内存分布及程序运行中(BSS段、数据段、代码段、堆栈
C语言中内存分布及程序运行中(BSS段.数据段.代码段.堆栈) - 秦宝艳的个人页面 - 开源中国 https://my.oschina.net/pollybl1255/blog/140323 Mem ...
- Cocos2d-x v3.11 中的新内存模型
Cocso2d-x v3.11 一项重点改进就是 JSB 新内存模型.这篇文章将专门介绍这项改进所带来的新研发体验和一些技术细节. 1. 成果 在 Cocos2d-x v3.11 之前的版本中,使用 ...
- java学习:JMM(java memory model)、volatile、synchronized、AtomicXXX理解
一.JMM(java memory model)内存模型 从网上淘来二张图: 上面这张图说的是,在多核CPU的系统中,每个核CPU自带高速缓存,然后计算机主板上也有一块内存-称为主内(即:内存条).工 ...
- Java并发(二):Java内存模型
一.硬件内存架构 一个现代计算机通常由两个或者多个CPU.其中一些CPU还有多核.每个CPU在某一时刻运行一个线程是没有问题的.如果你的Java程序是多线程的,在你的Java程序中每个CPU上一个线程 ...
- 深入理解JMM(Java内存模型) --(七)总结
JMM 掌管着一个线程对内存的动作 (读和写)影响其他线程对内存的动作的方式.由于使用处理器寄存器和预处理 cache 来提高内存访问速度带来的性能提升,Java 语言规范(JLS)允许一些内存操作并 ...
- Java内存模型深度解析:总结--转
原文地址:http://www.codeceo.com/article/java-memory-7.html 处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM和处理器内存模型在设计时通常会 ...
- java内存模型-总结
处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM 和处理器内存模型在设计时通常会把顺序一致性内存模型作为参照.JMM 和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照 ...
- 深入理解Java内存模型(七)——总结
处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM和处理器内存模型在设计时通常会把顺序一致性内存模型作为参照.JMM和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照顺序 ...
- 【转】深入理解Java内存模型(七)——总结
处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM和处理器内存模型在设计时通常会把顺序一致性内存模型作为参照.JMM和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照顺序 ...
随机推荐
- ibatis 中动态SQL查询和动态标签嵌套的使用
ibatis 动态查询对于从事 Java EE 的开发人员来说,iBatis 是一个再熟悉不过的持久层框架了,在 Hibernate.JPA 这样的一站式对象 / 关系映射(O/R Mapping)解 ...
- 一. python 安装
1. 下载安装包 1 2 3 https://www.python.org/ftp/python/2.7.14/python-2.7.14.amd64.msi # 2.7安装包 https: ...
- C# 基础回顾: volatile 关键字
有些人可能从来没看到过这个关键字,这也难怪,因为这个关键字并不常用.那这个关键字到底有什么用呢? 我在网上搜索这个关键字的时候,发现很多朋友都有一个错误的认识 ------ 认为这个关键字可以防止并发 ...
- OLED液晶屏幕(2)取模软件
https://blog.csdn.net/ling3ye/article/details/53399305 文件夹说明: Adafruit_SSD1306-master ——SSD1306库(O ...
- 实训作业6 (数据I/O)
1. 文件输出流的应用. 定义如下字符串: String str = “12345abcdef@#%&*软件工程”; 编写程序将该字符串写入文件”data.txt”. import java. ...
- Codevs 2009 大dota英雄 2013年省队选拔赛辽宁(状压DP)
2009 大dota英雄 2013年省队选拔赛辽宁 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 话说退役后的生活好无聊啊,以 ...
- 守护进程daemon.c
它的特点是:•不占用控制终端(后台运行)•独立于控制终端•周期性运行 #include<stdio.h>#include<unistd.h>#include<fcntl. ...
- 转载:基于 Hive 的文件格式:RCFile 简介及其应用---推酷
Hadoop 作为MR 的开源实现,一直以动态运行解析文件格式并获得比MPP数据库快上几倍的装载速度为优势.不过,MPP数据库社区也一直批评Hadoop由于文件格式并非为特定目的而建,因此序列化和反序 ...
- GoCN每日新闻(2019-10-18)
GoCN每日新闻(2019-10-18) 在Go1.13使用Errors https://blog.golang.org/go1.13-errors Go的扁平化应用结构 https://www.ca ...
- AT1879 2 つの山札
题面 题解 直接求解比较麻烦,考虑将问题进行转化. 设序列\(a = \{3, 1, 4, 2, 5\}, b = \{3, 2, 4, 1, 5\}\),那么我们构造一个正方形方格,将\(a\)放在 ...