缓存一致性

科技工作者之家 2020-11-17

在计算机科学中,缓存一致性(英语:Cache coherence,或cache coherency),又译为缓存连贯性缓存同调,是指保留在高速缓存中的共享资源,保持数据一致性的机制。

缓存一致性问题的提出计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中会涉及到数据的读取和写入。由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执行速度很快,而从内存读取数据和向内存写入数据的过程跟CPU执行指令的速度比起来要慢的多,因此如果任何时候对数据的操作都要通过和内存的交互来进行,会大大降低指令执行的速度。因此在CPU里面就有了高速缓存(Cache)的概念。当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。1

这一过程在单线程运行是没有问题的,但是在多线程中运行就会有问题了。在多核CPU中,每条线程可能运行于不同的CPU中,因此每个线程运行时有自己的高速缓存(对单核CPU来说,其实也会出现这种问题,只不过是以线程调度的形式来分别执行的)。这时CPU缓存中的值可能和缓存中的值不一样,这就是著名的缓存一致性问题2

在一个系统中,当许多不同的设备共享一个共同存储器资源,在高速缓存中的数据不一致,就会产生问题。这个问题在有数个CPU的多处理机系统中特别容易出现。

缓存一致性可以分为三个层级:

在进行每个写入运算时都立刻采取措施保证数据一致性

每个独立的运算,假如它造成数据值的改变,所有进程都可以看到一致的改变结果

在每次运算之后,不同的进程可能会看到不同的值(这也就是没有一致性的行为)

缓存一致性的解决方案为了解决缓存不一致性问题,通常来说有以下2种解决方法:

1.通过在总线加LOCK#锁的方式

2.通过缓存一致性协议

这2种方式都是硬件层面上提供的方式。

在早期的CPU当中,是通过在总线上加LOCK#锁的形式来解决缓存不一致的问题。因为CPU和其他部件进行通信都是通过总线来进行的,如果对总线加LOCK#锁的话,也就是说阻塞了其他CPU对其他部件访问(如内存),从而使得只能有一个CPU能使用这个变量的内存。在总线上发出了LCOK#锁的信号,那么只有等待这段代码完全执行完毕之后,其他CPU才能从其内存读取变量,然后进行相应的操作。这样就解决了缓存不一致的问题。3

但是由于在锁住总线期间,其他CPU无法访问内存,会导致效率低下。因此出现了第二种解决方案,通过缓存一致性协议4来解决缓存一致性问题。。最出名的就是Intel 的MESI协议,MESI协议保证了每个缓存中使用的共享变量的副本是一致的。它核心的思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。

MESI协议单核Cache中每个Cache line有2个标志:dirty和valid标志,它们很好的描述了Cache和Memory(内存)之间的数据关系(数据是否有效,数据是否被修改),而在多核处理器中,多个核会共享一些数据,MESI协议就包含了描述共享的状态。

在MESI协议中,每个Cache line有4个状态,可用2个bit表示,它们分别是:

M(Modified):这行数据有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中。

E(Exclusive):这行数据有效,数据和内存中的数据一致,数据只存在于本Cache中。

S(Shared):这行数据有效,数据和内存中的数据一致,数据存在于很多Cache中。

I(Invalid):这行数据无效。

在该协议的作用下,虽然各cache控制器随时都在监听系统总线,但能监听到的只有读未命中、写未命中以及共享行写命中三种情况。读监听命中的有效行都要进入S态并发出监听命中指示,但M态行要抢先写回主存;写监听命中的有效行都要进入I态,但收到RWITM时的M态行要抢先写回主存。总之监控逻辑并不复杂,增添的系统总线传输开销也不大,但MESI协议却有力地保证了主存块脏拷贝在多cache中的一致性,并能及时写回,保证cache主存存取的正确性。5

本词条内容贡献者为:

王慧维 - 副研究员 - 西南大学

科技工作者之家

科技工作者之家APP是专注科技人才,知识分享与人才交流的服务平台。