锁缓存行有一套协议叫做缓存一致性协议。缓存一致性协议有MSI、MESI、MOSI、Synapse、Firefly以及DragonProtocol等等。
MESI
MESI分别代表缓存行数据的4中状态,通过对这四种状态的切换,来达到对缓存数据进行管理的目的
状态 | 描述 | 监听任务 |
---|---|---|
Modified (修改) |
该Cache Line有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中 | Cache Line必须时刻监听所有试图读该Cache Line相对应的内存的操作,其他缓存须在本Cache Line写回内存并将状态置为E之后才能操作该Cache Line对应的内存数据 |
Exclusive (互斥) |
该Cache Line有效,数据和内存中的数据一致,数据只存在于本Cache中 | Cache Line 必须监听其他缓存读主内存中该Cache Line相对应的内存的操作,一旦有这种操作,该Cache Line需要变成S状态 |
Shared (共享) |
该Cache Line有效,数据和内存中的数据一致,数据同时存在于其他缓存中 | Cache Line必须监听其他处理器修改该Cache Line相对应的本地Cache Line的操作,一旦有这种操作,该Cache Line需要变成 I 状态 |
Invalid (无效) |
该Cache Line数据无效 | 无 |
多核缓存协同操作
假设有三个CPU-A、B、C,对应三个缓存分别是cache-a、b、c。在主内存中定义了x的引用值0
单核读取
- CPU-A发出一条指令,从主内存中读取x
- 从主内存通过bus读取到缓存中,此时该Cache Line修改为E状态
多核读取
- CPU-A发出了一条指令,从主内存中读取x
- CPU-A从主内存通过bus读取到cache-a中并将该Cache Line设置为E状态
- CPU-B发出一条指令,从主内存中读取x
- CPU-B试图从主内存中读取x时,CPU-A检测到了地址冲突。这时CPU-A对相应数据做出响应。此时x存在于cache-a和cache-b中,x在cache-a和cache-b中都被设置为S状态
修改数据 - CPU-A计算完成后发指令需要修改x
- CPU-A将x设置为M状态(修改)并通知缓存了x的CPU-B,CPU-B将本地cache-b中的x设置为I状态(无效)
- CPU-A对x进行赋值
同步数据
- CPU-B发出了要读取x的指令
- CPU-B通知CPU-A,CPU-A将修改后的数据同步到主内存时cache-a修改为E状态(独享)
- CPU-A同步CPU-B的x,将cache-a和同步后cache-b中的x设置为S状态(共享)
MESI优化和引入的问题:各CPU缓存行的状态是通过消息传递来进行的。如果CPU0要对一个在缓存中共享的变量进行写入,首先需要发送一个失效的消息给到其他缓存了该数据的CPU,并且要等到他们的确认回执。CPU0在这段时间内都会一直处于阻塞状态,会导致各种各样的性能问题和稳定性问题。
MESI性能优化
Store Buffer
为了避免阻塞带来的资源浪费,在CPU中引入了Store Buffer。
CPU在写入共享数据时,直接把数据写入到Store Buffer中,同时发送Invalidate消息,然后继续去处理其他指令。当收到其他所有CPU发送了Invalidate Acknowledge消息时,再将Store Buffer中的数据存储到Cache Line中,最后再从Cache Line同步到主内存。
Store Buffer的问题:引入了Store Buffer后,CPU会优先从Store Buffer中读取数据,这在一些情况下会导致CPU的乱序执行,也可以认为是一种重排序,这种重排序会带来可见性问题
网友评论