linux 内存屏障,理解内存屏障(一)
作者:新浪微博()
计算机学习微信公众号(jsj_xx)
1 前言
内存屏障是搞软件的需要面对的一个涉及硬件cpu的问题,很多人困惑不解。本文是我们对linux内核内存屏障的理解,参考linux内核(4.0版本)的Documentation/memory-barriers.txt。
2 内容
主要内容如下:2.1 内存访问的的抽象模型
2.2 什么是内存屏障
2.3 内核中的显式和隐式的内存屏障
2.4 cpu间的锁和屏障的关系
2.5 哪里需要使用屏障
2.6 内核中io屏障的作用
2.7 执行有序的最小假想模型
2.8 cpu cache对屏障的影响
2.9 alpha cpu
2.10 一个环形缓冲区的使用样例
好,让我们开始遐想(本文需要借助想象力,否则。。。)吧!
2.1 内存访问的抽象模型
如下图,多个cpu共同访问一个内存的场景(模型):
我们的理解是:只要能保证程序逻辑正确执行,cpu和complier(为了提升性能)怎么个乱序(优化)都行!
举例说明,如下:CPU 1CPU 2
==============================
{ A == 1; B == 2 }
A = 3;x = B;
B = 4;y = A;
cpu1有2条指令,cpu2也有2条指令,共4条指令,总共有24种执行顺序(其实就是4的阶乘),够多了吧!(更可怕的是,这还是建立在一个重要假设之下的:假设cpu上执行顺序和其它cpu感知的是一样的!否则。。。)
就这个例子而言,我们只关注x和y组成的可能结果,不外乎4种(其实就是2*2):x == 2, y == 1
x == 2, y == 3
x == 4, y == 1
x == 4, y == 3
再举个例子:CPU 1CPU 2
==============================
{ A == 1, B == 2, C = 3, P == &A, Q == &C }
B = 4;Q = P;
P = &BD = *Q;
只关注Q和D组成的结果的话,会出现“Q == 3”的结果么?cpu2这里有数据依赖性(或者说程序逻辑性):必须先取Q,再取*Q!这样看,cpu2肯定是先执行“Q = P”,所以一定不会出现“Q == 3”的结果了。
再看一个例子:*A = 5;
x = *D;
A是地址端口寄存器,D是数据端口寄存器。很明显,此时必须先放地址,再读数据,我们肯定认为只能这一种顺序,但是谁也保证不了!
至此,我们停顿下来,做个分析。貌似很乱了,软件根本搞不定,感觉是个硬件问题啊,那就让硬件做些限制(保证)吧!(cpu必须得做一些前提保证,否则软件世界大乱。。。)
前面说了,cpu会按照自己的(优化)顺序去执行指令,但一定不能违反一个大准则:程序本身的逻辑顺序。它会做如下保证:
1)有依赖的,保证保持现有顺序。
比如下面指针使用的例子:ACCESS_ONCE(Q) = P; smp_read_barrier_depends(); D = ACCESS_ONCE(*Q);
smp_read_barrier_depends()一般为空,也就是说大部分的cpu是(不需要特殊处理)保证这种顺序的:因为得保持程序自身的依赖关系!
2)保证对重叠操作的处理保序
所谓重叠操作就是对同一内存地址的连续处理。
比如:a = ACCESS_ONCE(*X); ACCESS_ONCE(*X) = b;
对地址X的处理顺序的两条指令就是重叠操作,cpu会保证现有顺序。
3)对毫无关系的指令,cpu保证你猜不出顺序!比如:X = *A; Y = *B; *D = Z;
这样的指令序列,会有几种可能的顺序?6种(3的阶乘)顺序,哪种都可能!
4)cpu保证对重叠部分可能合并,可能覆盖!
比如:X = *A; Y = *(A + 4);
此时可能有:X = LOAD *A; Y = LOAD *(A + 4);
Y = LOAD *(A + 4); X = LOAD *A;
{X, Y} = LOAD {*A, *(A + 4) };
再比如:X = *A; Y = *(A + 4);
此时可能有:STORE *A = X; STORE *(A + 4) = Y;
STORE *(A + 4) = Y; STORE *A = X;
STORE {*A, *(A + 4) } = {X, Y};
可见,重叠时,cpu可能会合并(又可能导致覆盖)。
cpu能做出以上保证,算给软件稍微(一点点)减负了。
特别需要注意的是位域结构:一般地,位域操作不是线程安全的!就是说,对同一个结构体内的不同位域成员(即使连续定义的成员)的多线程访问是无法保证线程安全的:Do not attempt to use bitfields to synchronize parallel algorithms.
我们来仔细分析这个问题,先看跟位域相关的一个memory location定义:memory location
either an object of scalar type, or a maximal sequence
of adjacent bit-fields all having nonzero width
所谓memory location,指的是一个标量类型对象或一个最大的连续非0长度位域组。特别地,0长度位域会单独霸占一个memory location,从而隔离出memory location!
那memory location到底对线程安全有何影响?对同一memory location的访问(包括更新)不是线程安全的;对不同memory location的访问(包括更新)则是线程安全的。
更具体地讲,对于一个结构体(各个字段的类型,可能是位域,也可能不是)而言,我们总结如下几个要点:位域类型和非位域类型之间的并发访问(包括更新),是线程安全(两个线程分别访问其中一个类型字段)的。
此结构体内部和该结构体的嵌套子结构体之间的位域字段,是线程安全的。
位域之间如果有0长度位域分割,则是线程安全的。
位域之间如果被一个非位域分割,则是线程安全的。
位域之间所有的位域都是非0位域,则是线程不安全的。
综上,要使访问位域线程安全化,可以采用锁,也可以在两个位域之间插入0长度位域(虽然有点浪费空间)。
好了,我们这次就讲到这里。总之,每个控制主体(compiler、各个cpu、程序逻辑本身)都会有自己所期望的顺序,那如何协调呢?下次开始讲什么是内存屏障。。。(未完待续)
关于我们
计算机学习微信公众号(jsj_xx)
原创技术文章,感悟计算机,透彻理解计算机!
linux 内存屏障,理解内存屏障(一)相关推荐
- linux性能优化实战-内存性能指标
转自:https://blog.csdn.net/san_77227487/article/details/87938546 https://blog.csdn.net/zxcc1314/articl ...
- Linux内核中的内存屏障(转)
转自:http://www.linuxidc.com/Linux/2011-10/44623.htm 前言 之前读了关于顺序一致性和缓存一致性讨论的文章,感觉豁然开朗.对linux内核中出现的种种同步 ...
- 【Linux 内核 内存管理】优化内存屏障 ④ ( 处理器内存屏障 | 八种处理器内存屏障 | 通用内存屏障 | 写内存屏障 | 读内存屏障 | 数据依赖屏障 | 强制性内存屏障 |SMP内存屏障 )
文章目录 一.处理器内存屏障 二.Linux 内核处理器内存屏障 一.处理器内存屏障 " 处理器内存屏障 " 针对 " CPU " 之间的内存访问乱序 和 CP ...
- 【Linux 内核 内存管理】优化内存屏障 ② ( 内存屏障 | 编译器屏障 | 处理器内存屏障 | 内存映射 I/O 写屏障 )
文章目录 一.内存屏障 二.编译器屏障 三.处理器内存屏障 一.内存屏障 内存屏障 , 又称为 " 屏障指令 " , 用于保证 " 编译器 " 或 " ...
- 内存访问顺序 - part2: 屏障及Linux kernel中屏障的使用
文章目录 屏障是什么 Linux Kernel 中的屏障 Linux 屏障 API 一般的屏障 强制性屏障 SMP 条件屏障 隐式屏障 其他屏障 屏障的开销 未来的文章 本文翻译自 Memory ac ...
- 全网最硬核 Java 新内存模型解析与实验 - 3. 硬核理解内存屏障(CPU+编译器)
个人创作公约:本人声明创作的所有文章皆为自己原创,如果有参考任何文章的地方,会标注出来,如果有疏漏,欢迎大家批判.如果大家发现网上有抄袭本文章的,欢迎举报,并且积极向这个 github 仓库 提交 i ...
- 浅谈内存屏障,C++内存序与内存模型
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可. 本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权. 文章目录 引言 一个有意思的问题 ...
- 内核同步机制-优化屏障和内存屏障
优化屏障 编译器编译源代码时,会将源代码进行优化,将源代码的指令进行重排序,以适合于CPU的并行执行.然而,内核同步必须避免指令重新排序,优化屏障(Optimization barrier)避免编译器 ...
- 一、barrier指令DSB,DMB,ISB,fence——内存屏障,指令屏障
最近工作中遇到一个问题,大致描述一下: 我们SOC用的arm cortex m7内核,在设计时设计人员图方便,将SPI controller的寄存器(即原本应该是APB空间)放在了0x60000000 ...
最新文章
- java spring注解教程,spring注解
- 近期热门领域新鲜数据集汇总!
- linux上很方便的上传下载文件工具rz和sz使用介绍
- 微软面向初学者的机器学习课程:1.3-机器学习中的公平性
- LeetCode 1832. 判断句子是否为全字母句
- node.js ajax success,前端如何通过ajax和node.js交互?
- 吴裕雄--天生自然 JAVASCRIPT开发学习: 表单验证
- POI导出Word插入复选框
- 什么样的领导会给公司造成损失呢?
- 基于Redis实现Spring Cloud Gateway的动态管理
- STM32与XY12864屏幕(ST7920中文显示模块)
- 魔兽世界服务器修改模型,修改模型教程!
- JAVA音频转换MP3转AMR互转
- 李斌转让5000万股私人持有股份 完成蔚来用户信托设立
- 微信小程序如何加密?
- Excel如何给单元格加斜线
- Windows 句柄泄露学习总结
- 为Windows 7的winsxs文件夹瘦身,慎重。
- 埃拉托色尼筛选法(Eratosthenes Sieve)分析
- 一图读懂腾讯云SaaS连接生态专场
热门文章
- 下拉框中select的onclick和onchange两个事件的区别
- python输入数据爬取_利用 Python 爬取高德地图数据
- 是不是不能用茶水喝药?
- 【AI with ML】第 14 章 :在 iOS 应用程序中使用 TensorFlow Lite
- Android 快速填满手机存储空间的方法
- 这篇文章可能会解决你PyQt5安装失败的问题
- 2020年广东省事业部联考回顾
- Dev-C++下载与安装(中文汉化版)
- 火影手游为什么服务器维护,火影忍者手游安装失败解决方法 游戏闪退进不去怎么办...
- 理解激活函数作用,看这篇文章就够了!