zoukankan      html  css  js  c++  java
  • volatile为什么可以保证内存可见性及防止指令重排序?

    内存

    共享主存和高速缓存(工作内存)。CPU高速缓存(L1,2)产生原因读写主存没有CPU执行指令快,他是某个CPU独有,只与该CPU运行的线程有关。

    内存可见性

    简单的说,CPU对数据的修改,对其他CPU立刻可见。下面我们详细地说。

    1. CPU修改数据,首先对工作内存修改,再同步主内存。单线程中,变量在工作内存的副本一直有效,CPU不用每次修改从主存读取变量,只是每次修改后同步主存。
    2. 对其他CPU立刻可见。当一个CPU修改变量,同步主存,如果其他CPU的工作内存也缓存这个变量,那么这个CPU的变量失效,当这个CPU想修改变量,必须从主存重新获取变量。

    volatile保证内存可见性基于MESI协议实现的。MESI协议是缓存一致性协议一种。

    题外话,如何保持CPU缓存一致性

    第一种,操作系统在总线上发出lock信号,其他处理器既不能操作缓存了该共享变量内存地址的缓存,阻塞其他CPU,使该处理器可以独享此共享内存。总线锁定把CPU和内存的通信锁住,使得其他处理器在锁定期间不能操作其他内存地址的数据。

    第二种,缓存一致性机制。当对某块CPU对缓存的数据操作后,通知其他CPU废弃存储在内部的缓存,或者从主存重新读取。

    MESI协议

    M:Modify,数据只在本CPU缓存,其他CPU没有,且数据修改没有更新到内存

    E:Exclusive, 独占。数据只在本CPU中缓存,且没有修改,即与内存中一致

    S:Shared,数据在多个CPU都有缓存,且与内存一致

    I:Invalid,本CPU中的这份缓存无效

    该协议要求每个缓存行维护上面4个状态中的2个状态。CPU修改数据,这个CPU的数据状态更新M,其他CPU的数据状态更新I。

    重排序

    保证缓存一致性,所以在CPU的L1缓存设置store buffer load buffer。导致CPU执行顺序和程序不一致。

    Memory Barrier

    1.分割代码,阻止栅栏前后没有数据依赖性的代码进行指令重排序,保证程序一定程度有序

    2.强制把store buffer/高速缓存的脏数据写回主存,缓存中相应数据失效,保证内存可见性

    StoreLoad Barrier保证barrier前所有内存访问指令完成后,才执行barrier后内存访问指令

    happens-before原则(重排序准则)

    1. 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;
    2. 锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作;
    3. volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;
    4. 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;
    5. 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;
    6. 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
    7. 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行; 对象终

    volatile

    采用memory barrier实现,保证可见性,禁止指令重排序,不保证原子操作。

    每个volatile写操作的前后插入一个StoreStore屏障
    每个volatile读操作的前后面插入一个LoadLoad屏障

    可看,https://blog.csdn.net/ysq222/article/details/88771218

  • 相关阅读:
    第二阶段站立会议05
    第二阶段站立会议04
    第一阶段冲刺总结
    站立会议08
    站立会议07
    站立会议06
    站立会议05
    站立会议04
    第一次冲刺第3天
    站立会议2
  • 原文地址:https://www.cnblogs.com/ivy-xu/p/12587833.html
Copyright © 2011-2022 走看看