一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情
CPU缓存一致性
CPU 缓存出现的原因
CPU
的运算速度是十分快的,而内存的数据交换速度远远小于CPU
。假如CPU
每次运算的时候都需要从内存拿数据,那么每一次计算就等待内存一次,这是十分不合理的,同样时间下,CPU
可以运算 100 次,而内存只能读一次数据。
由于上述问题,就像我们为了解决硬盘读取速度太慢而出现了内存这样子设计一样,计算机科学家同样创造除了CPU
缓存的概念。
CPU Cache的数据交换的基本单位
CPU
每次读取数据的时候不是一个一个字节从内存中进行读取的,CPU Line
是CPU
将数据从内存读取到CPU Cache
的基本单位。每个CPU Line
由Tag + Data Block
组成:
CPU Cache 的数据写入
为了保持CPU
缓存一致性,我们有两种CPU Cache
的数据写入机制,一种是写直达,一种是写回。
写直达
每次写数据的时候,同时将数据写入内存以及CPU Cache
中。
- 假如
CPU Cache
中没有对应的数据则直接将数据写入内存 - 如果
CPU Cache
中有对应的数据,那么数据同时写入内存以及Cache
写回
写直达的思路很简单,却也很影响效率,前面提到CPU
的运算的速度是远高于内存数据交换速度的,每次都写入内存会影响性能。
为了减少写回内存的次数,出现了写回的机制。(基于单核CPU
)
这个机制的思路也不难,当CPU
将数据写入CPU Cache
时,如果数据在Cache
中,则直接写入数据并标记脏。
如果数据对应的地址在Cache
中,则需要检查该数据是否为脏,是则将Cache
中的数据写回内存,并重新写入,最后再修改。
缓存一致性问题
刚刚说的都是单核CPU
情况下如何解决问题,实际上现在的计算机几乎都是多核CPU
并行运算的,因此我们不止要解决单核问题,还要解决多核问题,让我们来吧。
写传播
以往一个CPU
干活的时候,我将数据修改后,我自己直到就行,不需要通知其他几个兄弟。现在这个CPU
的兄弟多起来了,几个CPU
可能可以共同操作同一个共享变量,这里就涉及到并发安全问题:(以下事件顺序发生)
CPU
1将内存中的 A 变量写入了自己的Cache
,其值为 1CPU
2将内存中的 A 变量写入了自己的Cache
,其值为 1CPU
1修改变量 A ,使其加 1 ,变为 2CPU
2修改变量 A ,使其加 1 ,变为 2
可见,如果没有写传播机制,那么一个变量值被修改后,其值存放在CPU
自己的Cache
中,这个过程是不会被其他CPU
感知的。
事务的串行化
刚刚介绍的并发安全问题,其实我们也能看出问题,我们需要保证某个CPU
对共享变量的修改,在其他CPU
看来是串行化的,也就是说,CPU
1先修改了数据,CPU
2后修改了数据,那么其他的CPU
对于 A 这个变量的观察应该是,这个数据先后被CPU
1、2修改过。
==缓存一致性的解决==
通过写传播以及事务的串行化,我们可以解决CPU Cache
一致性问题l。
具体来说,是如何实现的呢?
总线嗅探
写传播的具体实现方式是总线嗅探。
总线嗅探的实现思路:
CPU
需要监控总线上的所有修改活动,如果某次修改是与自己缓存中的数据相关的,则将该修改更新到自己的缓存中。
事务的串行化
事务的串行化的具体实现方式是MESI
协议。
MESI
协议基于总线嗅探实现。