2018年4月1日 上午11:34

由于main mamory和cache的速度差异被拉大,所以加入了多级缓存。


参考:
他是个协议,MESI这个协议,为了保证多个CPU缓存中共享数据的一致性。
定义了cache的四种状态。
而CPU对cache的四种操作可能会产生不一致的状态。
因此缓存控制器,监听到本地操作和远程操作的时候。需要对cache状态做出一定的修改,从而保证数据在多个缓存之间流转的一致性。
SEMI其实是四个状态的缩写。
四种cache状态:2*2=4(是否独有 * 是否与内存一致)
- M:Modified被修改的。
- 处于这一状态的数据,只在本CPU中有缓存数据,而其他CPU中没有。
- 同时其状态相对于内存中的值来说,是已经被修改的,且没有更新到内存中。
- E:Exclusive独占的。
- 处于这一状态的数据,只有在本CPU中有缓存,
- 且其数据没有修改,即与内存中一致。
- S:Share共享的。
- 处于这一状态的数据在多个CPU中都有缓存
- 且与内存一致。
- I:Invalid 无效的。
- 本CPU中的这份缓存已经无效。
这里首先介绍该协议约定的缓存上对应的监听:
- 自己的状态受别的CPU影响。
- 一个处于M状态的缓存行
- 必须时刻监听,所有试图读取该缓存行对应的主存地址的操作
- 如果监听到,则必须在此操作执行前把其缓存行中的数据写回CPU。
- 一个处于S状态的缓存行
- 必须时刻监听,使该缓存行无效或者独享该缓存行的请求
- 如果监听到,则必须把其缓存行状态设置为I。
- 一个处于E状态的缓存行
- 必须时刻监听,其他试图读取该缓存行对应的主存地址的操作
- 如果监听到,则必须把其缓存行状态设置为S。
- 一个处于M状态的缓存行
- 当CPU需要读取数据时
- 一个invalid的缓存必须从主存中读取(变成S或者E状态)来满足该CPU的读请求
- 如果不是I,则可以直接读取缓存中的值,
- 但在此之前,必须要等待其他CPU的监听结果
- 如其他CPU也有该数据的缓存且状态是M,则需要等待其把缓存更新到内存之后,再读取。
- 当CPU需要写数据时
- 只有在其缓存行是M或者E的时候才能执行
- 否则需要发出特殊的RFO指令(Read Or Ownership,这是一种总线事务),通知其他CPU置缓存无效(I),这种情况下会性能开销是相对较大的。
- 在写入完成后,修改其缓存状态为M。
- 所以如果一个变量在某段时间只被一个线程频繁地修改,则使用其内部缓存就完全可以办到,不涉及到总线事务,
- 如果缓存一会被这个CPU独占、一会被那个CPU 独占,这时才会不断产生RFO指令影响到并发性能。
- 这里说的缓存频繁被独占并不是指线程越多越容易触发,而是这里的CPU协调机制,这有点类似于有时多线程并不一定提高效率,原因是线程挂起、调度的开销比执行任务的开销还要大,这里的多CPU也是一样,如果在CPU间调度不合理,也会形成RFO指令的开销比任务开销还要大。当然,这不是编程者需要考虑的事,操作系统会有相应的内存地址的相关判断,这不在本文的讨论范围之内。
- 并非所有情况都会使用缓存一致性的,如被操作的数据不能被缓存在CPU内部或操作数据跨越多个缓存行(状态无法标识),则处理器会调用总线锁定;另外当CPU不支持缓存锁定时,自然也只能用总线锁定了,比如说奔腾486以及更老的CPU。