一.CPU内存乱序访问发生的原因

(1)编译优化,指令重排导致乱序

由于编译器在编译代码时不感知多线程并发执行情况。所以,编译器对代码的优化是基于单线程执行情况,优化的结果就是导致多线程执行环境下CPU内存访问乱序问题。

(2)CPU运行,指令执行乱序

多核CPU并发执行,访问乱序。

在单核CPU 上,不考虑编译器优化导致乱序的前提下,多线程执行不存在内存乱序访问的问题。

二.内存屏障的作用

允许软件开发者使用硬件提供的特殊指令控制编译器和CPU的行为,在可能存在并发访问问题的点禁止编译器指令重排和CPU对指令乱序执行。

Linux内存屏障原语定义:

#define barrier() __asm__ __volatile__("": : :"memory")
#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)    #读写屏障
#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)   #读屏障
#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)    #写屏障#ifdef CONFIG_SMP#define smp_mb()        mb()#define smp_rmb()        rmb()#define smp_wmb()        wmb()#define smp_read_barrier_depends()        read_barrier_depends()#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
#else#define smp_mb()        barrier()#define smp_rmb()        barrier()#define smp_wmb()        barrier()#define smp_read_barrier_depends()        do { } while(0)#define set_mb(var, value) do { var = value; barrier(); } while (0)
#endif

三.什么时候用内存屏障

编译器开发者和cpu厂商都遵守着内存乱序的基本原则,简单归纳如下:
(1)不能改变单线程程序的执行行为 ,即单线程程序总是满足Program Order(所见即所得)。在此原则指导下,写单线程代码的程序员不需要关心内存乱序的问题。

(2)在多线程编程中,由于使用互斥量,信号量和事件都在设计的时候都阻止了它们调用点中的内存乱序(已经隐式包含各种内存屏障),内存乱序的问题同样不需要考虑了。

(3)只有当使用无锁(lock-free)技术时,即内存在线程间共享而没有任何的互斥量,内存乱序的效果才会显露无疑,这样我们才需要考虑在合适的地方加入合适的memery barrier。或者你希望编写诸如无锁数据结构,那么内存屏障还是很有用的。

四.Linux内存屏障原语的详细说明

内存屏障主要包括两类:编译器屏障 和 CPU屏障。

(1)编译器屏障

/* The "volatile" is due to gcc bugs */
#define barrier() __asm__ __volatile__("": : :"memory")
阻止编译器重排,保证编译程序时在优化屏障之前的指令不会在优化屏障之后执行。

(2)CPU屏障

通用 barrier,保证读写操作有序的,mb() 和 smp_mb()
写操作 barrier,仅保证写操作有序的,wmb() 和 smp_wmb()
读操作 barrier,仅保证读操作有序的,rmb() 和 smp_rmb()

Linux内存屏障使用注意事项:

(1)所有的 CPU Memory barrier(除了数据依赖barrier<smp_read_barrier_depends()>之外)都隐含了编译器barrier。

(2)这里的SMP开头的 Memory barrier会根据配置在单处理器上直接使用编译器 barrier,而在 SMP上才使用CPU Memory barrier(也就是 mb()、wmb()、rmb(),详见上面相关内核代码)。

(3)CPU Memory barrier中某些类型的Memory barrier需要成对使用——详细来说就是:一个写操作barrier<smp_wmb()>需要和读操作barrier<smp_rmb()>(或数据依赖barrier<smp_read_barrier_depends()>)一起使用(当然,通用barrier<smp_mb()>也是可以的),反之依然。

五.volatile关键字与内存屏障有关系吗

先说结论——没有关系。

编译器在编译用volatile关键字修饰的变量的时候,对于该变量的访问操作,生成的指令会直接去该变量对应的内存中取值,而不会用寄存器暂存该变量的中间结果。

也就是说volatile的目的是告诉编译器——不要优化对变量的访问方式,老老实实从内存中去读写。

下面是ACCESS_ONCE的实现:

#define __ACCESS_ONCE(x) ({ \__maybe_unused typeof(x) __var = (__force typeof(x)) 0; \(volatile typeof(x) *)&(x); })
#define ACCESS_ONCE(x) (*__ACCESS_ONCE(x))

其核心就是使用volatile来修饰变量。

CPU内存乱序访问与内存屏障相关推荐

  1. 简单理解计算机内存乱序

    作者 | 后端技术小牛说   责编 | 张文 头图 | CSDN 下载自视觉中国 本文探讨了自己对内存一致性模型的理解,由于不可避免的需要和操作系统底层打交道,本文主要例子和代码是 C++ 和汇编语言 ...

  2. CPU乱序发射与内存屏障

    CPU乱序发射与内存屏障 在提出问题之前,先看一段简单的代码. #include <stdio.h> #include <pthread.h> int x = 0, y = 0 ...

  3. 当我们在谈论cpu指令乱序的时候,究竟在谈论什么?

    原文:https://zhuanlan.zhihu.com/p/45808885 背景 在极客星球的群里面讨论 极客星球 很多现代高级语言多提供了多线程并发技术,今天服务器CPU基本上都是多核架构,在 ...

  4. 多线程安全小结-可见性(内存屏障,共享变量副本)、原子性、有序性(编译器优化、cpu流水线乱序)

    摘要: java多线程安全要满足:原子性.可见性.有序性. 手段有:不共享:不可变状态对象:互斥锁:同步工具类:线程安全工具类 本文为本人阅读<Java并发编程实战>的理解和总结,java ...

  5. 位域 内存 字节序_JS操作内存?二进制数组了解一下

    二进制数组的由来 主要是为了提高浏览器与显卡之间的通信效率,由二进制数据代替传统的文本. 二进制数组主要有三个对象: ArrayBuffer TypedArray DataView ArrayBuff ...

  6. DOS 实方式下直接访问4GB 内存

    十堰市湖北汽车工业学院电气工程系(442002) 陈家祺 摘 要: 分析了80486CPU 的寻址机制, 提出了在实方式下直接访问4GB 内存的策略和C 程序设计方法. 关键词: DO S 程序 扩展 ...

  7. JVM学习笔记之-对象的实例化,内存布局与访问定位,直接内存(Direct Memory)

    对象的实例化 对象的内存布局 图解 对象的访问定位 句柄访问 好处 reference中存储稳定句柄地址,对象被移动(垃圾收集时移动对象很普遍)时只会改变句柄中实例数据指针即可,reference本身 ...

  8. 无锁数据结构二-乱序控制(栅栏)

    内存栅栏 由于优化会导致对代码的乱序执行,在并发执行时可能带来问题.因此为了并行代码的正确执行,我们需提示处理器对代码优化做一些限制.而这些提示就是内存栅栏(memory barriers),用来对内 ...

  9. volatile关键字及编译器指令乱序总结

    本文简单介绍volatile关键字的使用,进而引出编译期间内存乱序的问题,并介绍了有效防止编译器内存乱序所带来的问题的解决方法,文中简单提了下CPU指令乱序的现象,但并没有深入讨论. 以下是我搭建的博 ...

  10. 小程序服务器内存要求,小程序服务器内存需要多大

    小程序服务器内存需要多大 内容精选 换一换 弹性伸缩服务可根据用户的业务需求,通过策略自动调整其业务的资源.具有自动调整资源.节约成本开支.提高可用性和容错能力的优势.适用以下场景:访问流量较大的论坛 ...

最新文章

  1. SO做了Booked之后,一直处理于“已延交”,发运事务处理的活动区变灰
  2. forward 和redirect的区别
  3. 深入浅出Mybatis系列(四)---配置详解之typeAliases别名(mybatis源码篇)
  4. LG卖楼进行时:价值87.7亿元的双子座大厦将出手
  5. Thunderspy: 7个硬件漏洞,影响9年来所有安装 Thunderbolt 的电脑
  6. 使用计算机粘贴板的步骤,电脑中快速打开剪贴板查看器的方法
  7. 迟来太久的2020年总结与2021展望
  8. 2019最新PayPal提现被退回的解决办法解析!
  9. CMS并发清理阶段为什么是安全的
  10. php课程设计感想,设计心得体会
  11. 90后大学生卖煎饼月收入4k
  12. python怎么用圆周率_用python程序求圆周率到任意位
  13. W10电脑U盘插入电脑不显示盘符但是“安全删除硬件并弹出媒体”中却有该U盘
  14. 生活随记-公平和本分
  15. 计算机 蓝牙鼠标卡顿,无线鼠标卡顿不流畅是什么原因_无线鼠标卡顿不流畅的处理方法...
  16. CAD怎么打印彩色图纸
  17. 多系统如何共享蓝牙设备?
  18. 多自由度有阻尼matlab,多自由度阻尼系统固有振型的MATLAB求解程序
  19. Android blueZ HCI(二):hcitool hcidump常用方法
  20. 一分钟攻破ADSL 盗遍宽带密码(转)

热门文章

  1. JavaScript进阶 | DOM
  2. php 悬浮按钮,Android_Android利用悬浮按钮实现翻页效果,今天给大家分享下自己用悬浮 - phpStudy...
  3. 挺苹果的声音,iPhone 5s的两处进步
  4. 微信中各种代码/符号合集
  5. ospf的链路更新—不同种类的LSA
  6. 大数据技术方面需要哪些支持
  7. 可爱精灵宝贝 动态规划讲解
  8. 计算机电脑主板电池,电脑主板电池怎么放电_主板电池放电要多久_电脑主板电池为啥要放电...
  9. 软件质量管理-6-质量管理
  10. React Suspense 尝鲜,处理前后端IO异步操作