MESI前情提要
如果一上来就讲最终boss ---- mesi会过于干了 可能记忆点比较难定位
因此我们可以先从cpu聊起
cpu和内存
我们知道cpu运行速度 > 内存速度
而且这个差距不是一般的大
对于木桶来说装下多少水取决于最短的那一块木板,一个响应也是
因此为了减少cpu和内存交互严重拖慢速度的情况下我们引入了多级缓存的概念
看见了吗 这里就是你cpu缓存使用的情况
cpu和缓存
那么和缓存是怎么解决速度上的不一致问题的呢?
其实cpu读取数据的时候尽可能从缓存中读取 而缓存中的数据是来自于内存的,相当于预读取了cpu需要的数据。
缓存和内存
那么内存是怎么读取内存中的数据的呢?
我们需要引入两个概念
在写回机制中,当发生写操作的时候,新的数据仅仅被写入缓存中,只有当修改过的缓存被替换的时候才需要写入到内存中(lazying load),减少了数据写回内存的频率,提高系统性能
保持内存和缓存一致性最简单的方式是,把数据同时写入内存和缓存中
多cpu的缓存一致性问题
上面的两种方案可以解决cpu 缓存 内存 的一致性问题 但是仅限于单核cpu
比如 cpu1 和 cpu2 共享一个变量i 这个时候cpu1修改了i但是修改之后的i不会被cpu2知晓,因为变量的更新只会在缓存中只有当前的数据被覆盖了才会写回到内存
多核cpu使用的多级缓存在上图介绍过了 因此需要什么标准来规定多核cpu缓存保证数据一致性呢
当一个cpu进行了写操作的时候也应该传播到其他的cpu,这一种的操作称为写传播
如果只有写传播也同样会出现问题,比如对于一个共享的变量进行不同的操作,cpu1是先进行cpu2后进行 写传播的时候cpu2的通知先到,cpu2的通知后到,这样肯定会出问题的
解决方案
写传播最常见的方式就是总线嗅探(bus snooping)
这一种实现的方式比较简单 当cpu修改了L1 cache中i变量的值,通过总线把这个事件广播给所有的核心 每一个cpu核心都会监听总线上的广播事件,并且检查是否偶相同的数据在自己的L1 cache里面,如果核心2的L1 cache中有该数据,那么也需要把数据更新到自己的L1 cache
总线嗅探只是保证了某一个cpu核心的cache更新数据这个事件能够被其他核心知道,但是并不能保证事务串行化
mesi 也就是俗称的缓存一致性协议
为4个单词的首字母组成
Modified Exclusive Shared Invalid
- modified(已修改)
这一种状态就代表前面起到的脏标记,代表该cache block上的数据已经被更新过了,但是还没有写入到内存中 - shared(共享)
表示cache block里面的数据是干净的,这个时候cache block里面的数据和内存里面的数据是一致性的
相同的数据在多个cpu核心的cache里面都有,所以我们需要更新cache里面的数据的时候不能直接修改,而是需要向所有其他cpu核心广播一个请求,要求把其他的cache 中对应的cache block 标记为无效状态,然后再更新当前cache里面的数据 - exclusive(独占)
cache block里面的数据已经失效了,不可以一读取该状态的数据
而且数据只能存储在一个cpu核心的cache里面,而且其他的cpu核心的cache没有改数据,这个时候要向独占cache写数据的时候就可以直接写入而不需要通知其他cpu核心,因为只有你有这个数据,不存在有一致性的问题
tips: 如果有其他核心从内存中读取到了相关的数据到各自的cache的时候独占状态就会变成共享状态 - invalidated(已失效)
这个状态表示这个cache block里面的数据已经失效了,不可以读取该状态的数据