MESI
- 在多核CPU中某核发生修改,可能产生数据不一致,一致性协议正是为了保证多个CPU cache之间的缓存共享数据的一致性。其中MESI对应modify(修改)、exclusive(独占)、shared(共享)、invalid(失效)。
| 状态 | 描述 |
|---|
| M(modify) | 该缓存行中的内容被修改了,并且该缓存行只缓存在该CPU中,而且和主存数据不一致 |
| E(exclusive) | 只有当前CPU中有数据,其他CPU中没有该数据,当前CPU和主存的数据一致 |
| S(shared) | 当前CPU和其他CPU中都有共同的数据,并且和主存中的数据一致 |
| I(invalid) | 当前CPU中的数据失效,数据应该从主存中获取 |
- 目前CPU的写,主要是2种策略
- 1、write back:即CPU向内存写数据时,先把数据写入store buffer中,后续某个时间点会将store buffer中的数据刷新到内存
- 2、write through:即CPU向内存写数据,同步完成写store buffer与内存
1、CPU异步完成写内存产生的延时是可以接受的,而且延迟很短,只有在多线程环境下需要严格保证内存可见等极少数特殊情况下才需要保证CPU的写在外界看来是同步完成的。
2、编译器和CPU可以保证输出结果一样的情况下对指令重排序。插入内存屏障,相当于告诉CPU和编译器先于这个命令的先执行,后于的命令必须后执行。
3、使用Lock前缀指令,会使多核心CPU互斥使用这个内存地址。当指令执行完,这个锁定动作也消失。
为什么还需要volatile?
- CPU的MESI能够保证缓存一致性,但是不能保证一个线程对变量修改后其他线程立即可见。
- 想象下:一个CPU0中的变量所在的cache line已经是invalid,但是在CPU1中缓存的该变量最新值还没有刷新到内存中。那么CPU0需要使用该变量,会从主存中读取到旧的值。
- 使用volatile可以保证可见性,该CPU该volatile修饰的变量的写操作立即同步到主存。而且volatile内存屏障的作用,也会将之前的发生的数据更新刷新到内存中。