作者:新浪微博()

计算机学习微信公众号(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 内存屏障,理解内存屏障(一)相关推荐

  1. linux性能优化实战-内存性能指标

    转自:https://blog.csdn.net/san_77227487/article/details/87938546 https://blog.csdn.net/zxcc1314/articl ...

  2. Linux内核中的内存屏障(转)

    转自:http://www.linuxidc.com/Linux/2011-10/44623.htm 前言 之前读了关于顺序一致性和缓存一致性讨论的文章,感觉豁然开朗.对linux内核中出现的种种同步 ...

  3. 【Linux 内核 内存管理】优化内存屏障 ④ ( 处理器内存屏障 | 八种处理器内存屏障 | 通用内存屏障 | 写内存屏障 | 读内存屏障 | 数据依赖屏障 | 强制性内存屏障 |SMP内存屏障 )

    文章目录 一.处理器内存屏障 二.Linux 内核处理器内存屏障 一.处理器内存屏障 " 处理器内存屏障 " 针对 " CPU " 之间的内存访问乱序 和 CP ...

  4. 【Linux 内核 内存管理】优化内存屏障 ② ( 内存屏障 | 编译器屏障 | 处理器内存屏障 | 内存映射 I/O 写屏障 )

    文章目录 一.内存屏障 二.编译器屏障 三.处理器内存屏障 一.内存屏障 内存屏障 , 又称为 " 屏障指令 " , 用于保证 " 编译器 " 或 " ...

  5. 内存访问顺序 - part2: 屏障及Linux kernel中屏障的使用

    文章目录 屏障是什么 Linux Kernel 中的屏障 Linux 屏障 API 一般的屏障 强制性屏障 SMP 条件屏障 隐式屏障 其他屏障 屏障的开销 未来的文章 本文翻译自 Memory ac ...

  6. 全网最硬核 Java 新内存模型解析与实验 - 3. 硬核理解内存屏障(CPU+编译器)

    个人创作公约:本人声明创作的所有文章皆为自己原创,如果有参考任何文章的地方,会标注出来,如果有疏漏,欢迎大家批判.如果大家发现网上有抄袭本文章的,欢迎举报,并且积极向这个 github 仓库 提交 i ...

  7. 浅谈内存屏障,C++内存序与内存模型

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可. 本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权. 文章目录 引言 一个有意思的问题 ...

  8. 内核同步机制-优化屏障和内存屏障

    优化屏障 编译器编译源代码时,会将源代码进行优化,将源代码的指令进行重排序,以适合于CPU的并行执行.然而,内核同步必须避免指令重新排序,优化屏障(Optimization barrier)避免编译器 ...

  9. 一、barrier指令DSB,DMB,ISB,fence——内存屏障,指令屏障

    最近工作中遇到一个问题,大致描述一下: 我们SOC用的arm cortex m7内核,在设计时设计人员图方便,将SPI controller的寄存器(即原本应该是APB空间)放在了0x60000000 ...

最新文章

  1. java spring注解教程,spring注解
  2. 近期热门领域新鲜数据集汇总!
  3. linux上很方便的上传下载文件工具rz和sz使用介绍
  4. 微软面向初学者的机器学习课程:1.3-机器学习中的公平性
  5. LeetCode 1832. 判断句子是否为全字母句
  6. node.js ajax success,前端如何通过ajax和node.js交互?
  7. 吴裕雄--天生自然 JAVASCRIPT开发学习: 表单验证
  8. POI导出Word插入复选框
  9. 什么样的领导会给公司造成损失呢?
  10. 基于Redis实现Spring Cloud Gateway的动态管理
  11. STM32与XY12864屏幕(ST7920中文显示模块)
  12. 魔兽世界服务器修改模型,修改模型教程!
  13. JAVA音频转换MP3转AMR互转
  14. 李斌转让5000万股私人持有股份 完成蔚来用户信托设立
  15. 微信小程序如何加密?
  16. Excel如何给单元格加斜线
  17. Windows 句柄泄露学习总结
  18. 为Windows 7的winsxs文件夹瘦身,慎重。
  19. 埃拉托色尼筛选法(Eratosthenes Sieve)分析
  20. 一图读懂腾讯云SaaS连接生态专场

热门文章

  1. 下拉框中select的onclick和onchange两个事件的区别
  2. python输入数据爬取_利用 Python 爬取高德地图数据
  3. 是不是不能用茶水喝药?
  4. 【AI with ML】第 14 章 :在 iOS 应用程序中使用 TensorFlow Lite
  5. Android 快速填满手机存储空间的方法
  6. 这篇文章可能会解决你PyQt5安装失败的问题
  7. 2020年广东省事业部联考回顾
  8. Dev-C++下载与安装(中文汉化版)
  9. 火影手游为什么服务器维护,火影忍者手游安装失败解决方法 游戏闪退进不去怎么办...
  10. 理解激活函数作用,看这篇文章就够了!