CPU缓存一致性
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
CPU缓存一致性
CPU Cache通常分为三级缓存L1CacheL2Cache,L3Cache级别越低的离CPU越近访问速度越快但同时容量越小价格越贵。在多核的CPU中每个核都有各自的L1L2Cache而L3是所有核共享的。
让我们先简单了解一下CPUCache的结构
CPU Cache是由很多个Cache Line组成的CPU Line是CPU从内存读取数据的基本单位而CPU Line是由各种标志Tag+数据块Data Block 组成
当我们读数据时首先在Cache中检测数据如果有的话则直接从Cache中读如果没有的话那么先从主存中读出来再存储在Cache中但是当我们在写数据时我们将数据在Cache中修改后那么Cache就和主存的数据不一致了那么我们应该在什么时候把数据写回到主存呐
写直达
写直达在写数据时把数据同时写入主存和Cache中
如果数据已经在Cache中先将数据更新到Cache里面再写入到主存里面
如果数据没有在Cache中就直接把数据更新到主存中
无论数据在没在Cache中最后都需要把数据写回到主存因为IO操作特别慢所以这会极大的影响效率
写回
为了减少IO操作所以就出现了写回的方法
在写回机制中当发生写操作时新的数据仅仅被写入Cache 中只有修改过的的Cache 块需要被替换时才写回到主存中。减少了IO操作这样可以大大提高程序的效率。
如果当发生写操作的时候数据已经在CPU cache中则把数据更新到CPU cache中同时标记CPU
cache里的 cache block为脏(Dirty)的(代表这个时候CPU cache里面的这个cache block的数据和
内存是不一样的)
- 如果当发生写操作数据所对应的cache block里存放的是其它的地址的数据A这个时候就要检测这个cacheblock里的A有没有标记为脏。 如果标记为脏我们就要把A写回到内存同时把要写入的数据写入到cache block中并标记为脏。
- 如果没有的话就直接将要写入的数据写入到cache block中再把这个数据标记为脏。
通过写回的话如果缓存命中的话可以大大提高我们的性能。
缓存一致性
现在CPU都是多核的由于L1/L2 cache都是每个核独自的这样就会带来多核的CPU缓存一致性的问题。
举例
假如core1,core2各自运行一个线程它俩同时对一个变量i初始值进行操作假如说core1对i进行++操作按照写回策略先把i的值写回到L1/L2 cache中再把它标记为脏这个时候core2对i操作的时候直接从内存中读值这个时候读到的值就是错误的因为刚才对i的操作还没有同步到内存中这就是缓存一致性问题。
要实现CPU缓存一致性的话我们就要保证
1.某个CPU核心李的cache 数据更新时必须传播到其它核心中的cache里这就是写传播。
2.某个CPU核心里对数据的操作顺序必须在其它核心看起来顺序是一样的这就是事务的串行化。
我们简单解释一下事务的串行化
假如说有一个4核的CPU这4个core都操作同一个变量初始值为0core1先把i变为100而同一时间core2再把值变为200根据写传播这两个操作都会传播到core3,core4。
- 假如说core3先接收了core1的操作再收到了core2的操作那么对与core3来说i的值此时i的值就是200。
- 假如说core4相反先接收了core2的操作再收到了core1的操作那么对于core4来说此时i的值就是100。
所以我们要保证所有的核心看到的都是相同顺序的变化这样的过程就是事务的串行化。
总线嗅探
写传播最常见的方式就是总线嗅探。
实现原理每个CPU都监听总线上的广播事件并检查是否有相同的数据在自己的L1/L2缓存中如果有的话则自己也需要把该数据更新。
MESI协议
MESI协议基于总线嗅探机制实现了事务串行化也用状态机机制降低了总线带宽压力。
MESI协议其实就是4个状态单词的开头字母缩写
- Modified 已修改
- Exclusive 独占
- Shared 共享
- Invalidated 已失效
用这四个状态来标记cache Line四个不同的状态。
已修改状态就是我们前面提到的脏标记代表该cache block上的数据已经被更新过但是还没有写到内存里。
已失效状态 表示的是这个cache block里的数据已经失效了不可以读取该状态的数据。
独占和共享都代表cache block里的数据是干净的cache block和内存里面的数据是一致的)。
独占和共享的差别在于独占状态的时候数据只存储在一个CPU的cache中而其它CPU cache里面没有该数据。这个时候如果要向独占的cache写数据就可以自由的写入而不需要通知其它CPU core。而如果有其它core从内存读取了相同的数据到自己的cache中那么独占的数据就会变为共享状态。
共享状态代表着相同的数据在多个CPU核心的cache里面都有所以当我们要修改cache里面的数据时不能直接修改而是要先向所有其它的core广播一个请求要求先把其它core中cache中对应的cache line标记为无效状态然后再更新当前cache里面的数据。