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和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照顺序 ...
随机推荐
- Dynamics CRM 数据数量限制更改
1.在CRM2016中如果想要导出超过10000记录数据,更新 MaxRecordsForExportToExcel 这个字段的值. SELECT MaxRecordsForExportToExce ...
- C++异常处理(二)----声明接口
接口声明的三种形式 抛出一切形式的异常 void freeobj(mycoach &t) { ) { cout <<"精神可嘉~但还是年龄太小" << ...
- ssh配置基础
1:hostname r12:R1(config)#username xxx secret ppp3:R1(config)#ip domain-name baidu.com 设置域名4:R1(conf ...
- width: calc(100% - 80px); 屏幕自适应方法
width: calc(100% - 80px); 屏幕自适应方法
- c# NPOI aspx导出数据
public static class XSSFWorkbook_Excel { /// <summary> /// GetExcel /// </summary> /// & ...
- MongoDB 红宝书-MongoDB官网使用指南
本文转载自Mongodb中文社区:http://www.mongoing.com/archives/27359 无论你是MongoDB的使用者.爱好者.初学者还是路人甲,有一个学习与进修的资源宝藏是千 ...
- web大附件上传,支持断点续传
一. 功能性需求与非功能性需求 要求操作便利,一次选择多个文件和文件夹进行上传:支持PC端全平台操作系统,Windows,Linux,Mac 支持文件和文件夹的批量下载,断点续传.刷新页面后继续传输. ...
- windows 获取时间戳
Windows 批处理时间戳 1.时间戳格式: 取年份: echo %date:~,% 取月份: echo %date:~,% 取日期: echo %date:~,% 取星期: echo %date: ...
- 洛谷 P3183 [HAOI2016]食物链 题解
P3183 [HAOI2016]食物链 题目描述 如图所示为某生态系统的食物网示意图,据图回答第1小题现在给你n个物种和m条能量流动关系,求其中的食物链条数.物种的名称为从1到n编号M条能量流动关系形 ...
- 【JOISC2018|2019】【20190622】mergers
题目 一\(n\)个节点的树,节点被分成\(k\)个集合,\(i\)属于\(S_i\), 一条边是可划分的当且仅当左右两边的子树不存在相同集合的点 你一次可以合并两个集合,求最少的操作次数使得所有边都 ...