码迷,mamicode.com
首页 > 编程语言 > 详细

volatile为什么可以保证内存可见性及防止指令重排序?

时间:2020-03-28 16:29:56      阅读:158      评论:0      收藏:0      [点我收藏+]

标签:防止   odi   mes   ref   thread   排序   工作   规则   详细   

内存

共享主存和高速缓存(工作内存)。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

volatile为什么可以保证内存可见性及防止指令重排序?

标签:防止   odi   mes   ref   thread   排序   工作   规则   详细   

原文地址:https://www.cnblogs.com/ivy-xu/p/12587833.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!