【Java并发编程与高并发解决方案】CPU多级缓存与缓存一致性(
2018-10-29 本文已影响0人
留夕_3826
开始搞起来吧。这周先把多线程的各个细节搞好他。最好能整理出文字性的东西吧。现在开始第一天吧~
-
CPU多级缓存
-
一级缓存太贵,所以有有了二级、三级缓存
image.png
-
-
为啥要cache
image.png -
cache容量有限,命中率低,为啥还要他。
image.png -
缓存一致性 MESI
image.png
开始搞cpu、内存、缓存之间的关系
- 绝大多数 的内存访问都需要通过层层的缓存来进行
- CPU正常情况下不能直接访问内存,物理决定。只能通过多级缓存来访问内存
- 先来个笼统一点的概念
- 缓存段,一段和缓存大小对其的内存。
如果只是读的情况
这种情况下,任意时刻,缓存中缓存段的内容和内存中对应的内容是一致的。
- cpu首先发出读指令,把内存地址给到cache
- cache会检查是否有这个地址对应的缓存段,如果没有,会从内存(或者更下一级,二级之类的缓存)中把这一个缓存段全部存到一级缓存中。
- 数据被加在到一级缓存后,cpu就可以正常读取了
如果考虑写的情况
记住一条:当所有脏数据都被回写后,任一级别缓存中所有缓存段的数据和内存中对应的数据是一致的。
- 写的情况,分为直写(write-through)和回写(write-back)
- 直写:如果对应缓存中的段被更新了,那他的下一级缓存或者内存也应该同步被更新。
- 回写:如果对应缓存中的段被更新了,不会立即被写到下一级缓存或者内存,而是被标记为了脏段。脏段会在特定的时刻(具体啥时候下面会详细说)触发回写。也就是说,脏段在被丢弃的时候,总是要先进行一次回写。
- 这个地方就没有任何时刻了,因为回写模式有脏数据的存在。
- 虽然直写看上去更简单,但是回写模式可以避免对同一片地址的反复操作,可以一次性写一大片内存。
一致性协议
上面扯的那些都是在只有一组缓存的情况下,如果有多个cpu对应多组缓存,如果某一组缓存段对应的内存地址中的数据被另一个cpu给修改了,会发生什么。
- 那啥,很遗憾的是,如果被其他的cpu给修改了,另外的缓存是无法得知这一更改的,这就破坏了一致性。
- 为啥不是多核cpu只对应一组缓存呢。
- 当然是效率问题啦,并发情况下出现问题不都是因为效率问题导致的吗。
- 因为在每一个时钟或者指令周期,都只能有一个cpu通过缓存对内存进行操作,其他的cpu就进入了等待。流水线就产生了冒泡。会极大浪费硬件资源~
- 所以引入多组缓存,使他们用起来的效果像只有一组缓存一样,这个协议就是保持了多组缓存之间的一致性。
- 这个缓存一致性协议有很多种,最常用的是窥探snooping协议。
- 内存在这里是共享资源,所有cpu对于内存的操作都要经过仲裁:
- 所有对于内存的操作都经过同一条总线,所有的缓存组都挂在这个总线上。
- 缓存不只有在与内存发生数据交换的时候才和总线打交道,他会无视无可关注其他处理器对于内存的操作。
- 当一个处理器通过缓存执行了对于内存的修改,其他的缓存组就可以窥探到这一个操作,使自己的缓存中对应的缓存段失效或者更新。
- 内存在这里是共享资源,所有cpu对于内存的操作都要经过仲裁:
MESI缓存一致性协议
- 上面说的那种方式,在直写模型中没有任何问题,但如果到了回写模型,就会有问题了。
- 有可能在某一组缓存中已经产生了脏数据,但是此刻并没有发生回写,所以其他内存组没办法知道这一变化,还是拿了内存中的数据。
- 这时候只需要做的是,在产生脏数据之前,要把这一变化sync到其他的缓存组。这就是MESI协议啦。
-
MESI是Modified、Exclusive、Shared、Invalid的首字母缩写,代表四种缓存状态。下面就详细说一下这四种状态。
- Invalid 失效缓存段,这种状态下可以认为是缓存中没有这个内存地址对应的缓存段。
- Shared 共享缓存段。是一份和主存中一摸一样的拷贝。这时候只能读不能写。多组缓存段都拥有对于这个数据的拷贝。
- Exclude 独占缓存段。有一份与主存一摸一样的拷贝。区别在于其他缓存段不能同时持有他,当某个缓存段处于这一状态,其他缓存段中,对应统一内存地址的缓存段就变为了Invalid状态。
- Modified 修改缓存段。此时缓存段的状态是脏段,其他处理器缓存中的拷贝都变为Invalid。如果此段缓存要失效或被丢弃,需要把数据回写到内存。
-
好啦,上面比比了那么多,一开始所说的“一组缓存在修改前,如何通知到其他缓存的问题”已经得到了解决。
- 只有在M或者E状态下(获取了独占权)的缓存才能被进行写操作,如果没有获取到独占权,就要通知总线上的其他缓存,此时其他处理器缓存中对应的数据就变为了Invalid状态。
- 如果有其他处理器想读这块内存,那么M状态下写的数据就会被写回到内存,这时候就变成了Shared状态。
1.在多核系统中,读取某个缓存段,实际上会牵涉到和其他处理器的通讯,并且可能导致它们发生内存传输。写某个缓存段需要多个步骤:在你写任何东西之前,你首先要获得独占权,以及所请求的缓存段的当前内容的拷贝(所谓的“带权限获取的读(Read For Ownership)”请求)。
2.尽管我们为了一致性问题做了额外的工作,但是最终结果还是非常有保证的。即它遵守以下定理,我称之为:MESI定律
- 在所有的脏缓存段(M状态)被回写后,任意缓存级别的所有缓存段中的内容,和它们对应的内存中的内容一致。此外,在任意时刻,当某个位置的内存被一个处理器加载入独占缓存段时(E状态),那它就不会再出现在其他任何处理器的缓存中。