E(Exclusive) 表示缓存的独占状态,数据只缓存在当前CPU缓存中,并且没有被修改(独占状态只有一个CUP 有数据)
S(Shared) 表示数据可能被多个CPU缓存,并且各个缓存中的数据和主内存数据一致
I(Invalid) 表示缓存已经失效
总线锁和缓存锁怎么选择,取决于很多因素,比如CPU是否支持、以及存在无法缓存的数据时
(比较大或者快约多个缓存行的数据),必然还是会使用总线锁。
对于 MESI 协议,从 CPU 读写角度来说会遵循以下原则:
CPU 读请求:缓存处于 M、E、S 状态都可以被读取,I 状 态 CPU 只能从主存中读取数据。
CPU 写请求:缓存处于 M、E 状态才可以被写。对于 S 状 态的写,需要将其他 CPU 中缓存行置为无效才可写 使用总线锁和缓存锁机制之后,CPU 对于内存的操作大概 可以抽象成下面这样的结构。从而达到缓存一致性效果。
5.MESI 优化带来的可见性问题
CPU 缓存行的状态是通过消息传递来进行的,如果 CPU0 要对一个在缓存中共享的变量进行写入,首先发送一个失效的消息给到其他缓存了该数据的 CPU。并且要等到他们的确认回执。CPU0 在这段时间内都会处于阻塞状态。
为了避免阻塞带来的资源浪费。在 cpu 中引入 了 Store Bufferes(存储缓存) 和 Invalidate Queue(无效队列)。
CPU0 写入共享数据时,直接把数据写入到 store bufferes 中,同时发送 invalidate 消息,然后继续去处理其他指令。
当收到其他所有 CPU 发送了 invalidate ACK消息时,再将 store bufferes 中的数据数据存储至 cache 中。最后再从本地Cache同步到主内存。
但是 cpu 中引入 Store Bufferes 优化存在两个问题:
第⑥、⑦步骤中,由于Invalidate消息进入队列后就给CPU-0返回了响应,不能保证第⑦步骤一定完成。
引入了 Store Bufferes 后,处理器会先尝试从 Store Bufferes 中读取值,如果 Store Bufferes 中有数据,则直接从Store Bufferes 中读取,否则就再从本地Cache中读取,从Store Bufferes读取数据存在脏读。