欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

什么是缓存一致性问题?如何解决呢?

程序员文章站 2022-05-28 21:17:52
当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU高速缓存中,那么CPU进行计算时就可以从它的高速缓存读取数据和向其中写入数据,当运算结束后,再将高速缓存中的数据刷新到主存当中。举个简单的例子,比如下面的这段代码: i = i+1; 当线程执行这个语句时,会先从主存当中读取i的值,然后复制 ......

  当程序在运行过程中,会将运算需要的数据从主存复制一份到cpu高速缓存中,那么cpu进行计算时就可以从它的高速缓存读取数据和向其中写入数据,当运算结束后,再将高速缓存中的数据刷新到主存当中。举个简单的例子,比如下面的这段代码:

i = i+1;

   当线程执行这个语句时,会先从主存当中读取i的值,然后复制一份到高速缓存当中,然后cpu执行指令对i指令进行加1操作,然后将数据写入高速缓存,最后将高速缓存中i最新的值刷新到主存当中。

  这个代码在单线程中运行时没有任何问题的,但是在多线程中运行就会有问题了。在多核cpu中,每条线程可能运行于不同的cpu中,因此每个线程运行时有自己的高速缓存(对单核cpu来说,其实也会出现这种问题,只不过是以线程调度的形式来分别执行的)。我们以多核cpu为例。

  比如同时有两个线程执行这段代码,假如初始时i的值为0,那么我们希望两个线程执行完之后i的值变为2。但事实会是这样吗?

  可能存在下面一种情况:初始时,两个线程分别读取i的值存入各自所在的cpu的高速缓存当中,然后线程1进行加1操作,然后把i的最新值1写入到内存。此时线程2的高速缓存当中i的值还是0,进行加1操作后,i的值为1,然后线程2把i的值写入内存。

  最终结果i的值是1,而不是2。这就是著名的缓存一致性问题。通常称这种被多个线程访问的变量为共享变量。

  也就是说,如果一个变量在多个cpu中都存在缓存(一般在多线程编程时才会出现),那么就可能存在缓存不一致的问题。

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

    1)通过在总线加lock,锁的方式;

    2)通过缓存一致性协议

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

  但是上面的方式会有一个问题,由于在锁住总线期间,其他cpu无法访问内存,导致效率低下。

  所以就出现了缓存一致性协议。该协议保证了每个缓存中使用的共享变量的副本是一致的。它的核心思想是:当cpu向内存写入数据时,如果发现操作的变量时共享变量,即在其他cpu中也存在该变量的副本,会发出信号通知其他cpu将该变量的缓存行置为无效状态,因此当其他cpu需要读取这个变量时,发现自己缓存中缓存该变量的缓存是无效的,那么它就会从内存重新读取。