概要:2cache的写操作、3状态介绍、4MESI协议状态迁移、5内存屏障
volatile底层是 Lock前缀的汇编指令,通过锁Cacheline实现
一、CPU缓存一致性协议MESI
内存中数据在多个核心中存数据副本,某一修改,产生不一致
二、cache的写操作
1、write through 写通:CPU修改cache立即更新到内存,共享数据导致总线事务,引起竞争,一致性高但效率低
2、write back 写回:不会立即更新到内存,等cacheline某一必须或合适的才更新内存
3、写失效:当CPU修改数据,其他CPU有该数据,通知其无效
4、写更新:CPU修改数据,其他CPU有该数据,通知其更新
5、cacheline:cache与内存数据交换的最小单位,根据操作系统32或64byte,MESI协议中状态可是M、E、S、I,地址是cacheline映射内存地址,数据从内存中读
5、工作方式:
CPU从cache读,会比较地址是否相同,1)相同则检查cacheline状态,再决定该数据是否有效,2)无效则从主存中获取,根据一致性协议发生一次cache-to-cache数据推送
6、工作效率
当CPU能从cache拿有效数据时,消耗几个CPU cycle,如缓存中没有数据要从主存中读,则会消耗几十上百个CPU cycle。
三、状态介绍
MESI协议将cacheline状态分modify修改、exclusive独占、shared分享、invalid失效
M(modify):CPU改完数据,当前CPU有最新,其他有失效数据,且和主存数据不一致
E(exclusive):只当前CPU有数据,其他CPU没有,当前CPU的数据和主存数据是一致
S(shared):当前CPU和其他有共同数据,并且和主存中数据一致
I(invalid):当前CPU中数据失效,应从主存中获取,其他CPU中可能有/也可能无数据;当前CPU中的数据和主存中的数据被认为不一致
ps:M和E的Cache Line独有数据,M时dirty和内存不一致,E一致
四、MESI协议状态迁移
MESI协议中,每个Cache控制器不仅知道自己读写操作,也监听其他Cache读写,每个Cache line所处状态根据本核/其他核读写操作在4个状态间进行迁移
读本cache LocalRead; 写本cache LocalWrite;
读其他cache Remote Read; 写其他cache Remote Write;
五、内存屏障
作用1:编译器和CPU保证输出结果一样时对指令重排序,优化性能,插入内存屏障,相当于告诉CPU和编译器,先于这命令先执行,后于后执行
作用2:强制更新不同CPU缓存,对volatile字段写,线程会得最新值
六、Volatile如何保证可见性
1、加入volatile时多出lock前缀指令(相当于内存屏障),三个功能:
1)确保指令重排序时,后面指令不会重排到内存屏障前,前面指令不排到内存屏障后,执行内存屏障指令时,前面已完成
2)将当前处理器缓存行数据立即写回系统内存(由volatile先行发生原则保证);
3)写回内存操作引起,其他CPU里缓存该内存地址数据无效。写回要总线传播数据,嗅探总线数据,检查是否过期,1)发现内存地址被修改,缓存行为无效状态,值修改,会强制重新从系统内存读到处理器缓存(由volatile先行发生原则保证);
2、缓存一致性协议有多种,大多数都属于”嗅探(snooping)”协议:
1)内存传输都发生在一条共享总线上,内存访问要经过仲裁(同一指令周期中,只有一个CPU缓存可读写内存)
2)CPU缓存不停嗅探总线上的数据交换、其他缓存在做什么。缓存(代表它所属的处理器)去读写内存时,通知其它处理器保持同步:写内存,其它知道这块内存在它们缓存段中已失效
3、lock指令的几个作用(反复思考IA-32手册对lock指令描述得出):
1)锁总线,实际锁缓存替代锁总线,锁总线开销大,其它CPU对内存读写阻塞,直到释放
2)lock后,写操作回写已修改数据,同时让其它失效,重新加载(从主内存)
3)类似内存屏障功能,阻止屏障两遍指令重排序
七、既然CPU有MESI协议可保证cache的一致性,为什么还需要volatile证可见性(内存屏障)?
或者是只有加volatile,多核cpu执行时,才会触发缓存一致性协议?
1、多核情况下,校验缓存一致性,但弱一致。volatile立即刷新存,修改操作和写回是原子操作
2、正常不校验缓存一致性,只有volatile修饰,才校验
volatile的使用场景:状态标志(开关模式)、双重检查锁定、需要利用顺序性