缓存一致性的意义是什么?

13
在像x86这样提供缓存一致性的CPU上,从实际角度来看这有什么用呢?我知道这个想法是使得在一个核心上进行的内存更新立即在所有其他核心上可见。这是一个有用的特性。然而,如果不编写汇编语言,人们不能过度依赖它,因为编译器可以将变量分配存储在寄存器中,而从未将它们写入内存。这意味着人们仍必须采取明确的步骤,以确保在当前线程中可见其他线程完成的工作。因此,从实际角度来看,缓存一致性达成了什么效果?
6个回答

10
简单来说,非缓存一致性系统在编程方面特别困难,尤其是如果想要保持效率的话——这也是为什么大多数NUMA系统今天都是缓存一致性的主要原因。
如果缓存不一致,"显式步骤"必须强制执行一致性——显式步骤通常是关键部分/互斥锁(例如,在C/C++中的volatile很少足够)。对于像互斥锁这样的服务来说,仅跟踪已更改并需要在所有缓存中更新的内存非常困难,甚至可能必须更新所有内存,并且只有它可以跟踪哪个核心拥有那些内存片段。
硬件可以更好地有效地跟踪已更改的内存地址/范围,并使其保持同步。假设一个进程在核心1上运行并被抢占了。当它再次被调度时,它被调度到核心2上。如果缓存不一致,这将非常致命,因为核心1的缓存中可能仍然存在进程数据的遗留,而在核心2的缓存中则不存在。尽管如此,对于工作方式的系统,操作系统将在线程被调度时强制实施缓存一致性,这可能是一个"更新所有缓存中的内存"操作,或者它可以借助MMU跟踪脏页,并仅同步已更改的内存页面——再次强调,硬件可能以更细粒度和更有效的方式使缓存保持一致。

核之间的进程迁移并不是非常频繁,因此为任何失去进程的核刷新写缓存的成本,或为任何获得进程的核刷新读缓存的成本,真的不应该是太大的问题。更大的问题是,如果进程#1在核A和B上运行,而进程#2在C和D上运行,则核C和D不应该需要投入任何资源来监视由核A和B代表进程#1进行的内存访问,因为这些内存区域实际上不应该是感兴趣的。 - supercat

9
其他作者的回答中有一些细节没有涵盖。首先,需要考虑到CPU不是按字节处理内存,而是按缓存行处理。一个缓存行可能有64个字节。现在,如果我在位置P上分配了一个2字节的内存块,另一个CPU在位置P+8上分配了一个8字节的内存块,并且P和P+8都在同一个缓存行上,那么没有缓存一致性,两个CPU不能同时更新P和P+8而不互相干扰彼此的更改!因为每个CPU对缓存行进行读取-修改-写入操作,它们可能都会写出不包括另一个CPU更改的缓存行的副本!最后的写入者将获胜,你对内存的修改之一将“消失”!
另一件需要注意的事情是一致性和一致性之间的区别。因为即使基于x86的CPU使用存储缓冲区,也不能保证已经完成的指令已经以其他CPU可以看到这些修改的方式修改了内存,即使编译器决定将值写回内存(也许是因为volatile?)。相反,修改可能会在存储缓冲区中等待。几乎所有常用的CPU都是具有缓存一致性的,但非常少数的CPU具有与x86一样宽容的一致性模型。例如,可以查看http://www.cs.nmsu.edu/~pfeiffer/classes/573/notes/consistency.html获取有关此主题的更多信息。
希望这可以帮助你。顺便说一下,我在Corensic工作,这是一家正在构建并发调试器的公司,您可能想要查看。当关于并发性、一致性和一致性的假设被证明是不可靠的时,它有助于拾起碎片 :)

1
无法访问链接。错误403。 - Ayrat

7

假设您这样做:

lock(); //some synchronization primitive e.g. a semaphore/mutex
globalint = somevalue;
unlock();

如果没有缓存一致性,那最后一个 unlock() 必须确保 globalint 在任何地方都是可见的。有了缓存一致性,你只需要将其写入内存,让硬件完成魔术即可。软件解决方案必须跟踪存在于哪个缓存、在哪个核心上的哪些内存,并确保它们原子地同步,如果你能找到比当前硬件解决方案更有效的软件解决方案来跟踪所有需要保持同步的缓存中存在的所有内存块,那么你将赢得奖项。

但在您的示例中,编程人员显然知道他们正在写入全局值,并且他们可以包括刷新/同步原语以确保对globalint的写入传播到其他核心。或者我们可以在库级别处理此问题,通过在unlock()方法中放置同步原语。因此,我不确定这个示例是否是回答问题的好方法。您必须展示为什么上述两种方法之一也无法起作用。 - Evan Cox

1

当你处理多个线程并从多个线程访问同一变量时,缓存一致性变得非常重要。在这种情况下,你必须确保所有处理器/核心在同时访问变量时看到相同的值,否则你将会遇到非常不确定的行为。


1

这并不需要锁定。如果需要,锁定代码将包括缓存刷新。主要需要确保不同处理器对同一缓存行中的不同变量进行的并发更新不会丢失。


0

硬件实现了缓存一致性,因为程序员不必担心在多核/多处理器环境下操作时所有线程是否看到内存位置的最新值。缓存一致性提供了一个抽象,即所有核心/处理器都在单个统一缓存上运行,尽管每个核心/处理器都有自己的独立缓存。

它还确保传统的多线程代码在新的处理器型号/多处理器系统上正常工作,而无需进行任何代码更改以确保数据一致性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接