首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >内存障碍强制缓存一致性?

内存障碍强制缓存一致性?
EN

Stack Overflow用户
提问于 2015-06-20 20:05:09
回答 3查看 3.7K关注 0票数 10

我当时正在读关于使用bool进行线程控制的问题。,对@eran的回答很感兴趣:

仅在单个内核上使用易失性就足够了,所有线程都使用相同的缓存。在多核上,如果在一个内核上调用stop(),而在另一个内核上执行run(),则可能需要一段时间才能使CPU缓存同步,这意味着两个内核可能会看到isRunning_的两个不同视图。 如果使用同步机制,它们将确保所有缓存都得到相同的值,代价是使程序延迟一段时间。性能或正确性对您来说是否更重要,取决于您的实际需求。

我花了一个多小时寻找一些语句,这些语句说同步原语会强制缓存一致性,但是失败了。我来得最近的是维基百科

关键字易失性不能保证内存屏障来执行缓存一致性。

这表明内存屏障确实会强制缓存一致性,而且由于一些同步原语是使用内存屏障(同样来自Wikipedia)实现的,这是一些“证据”。

但我不知道是否相信这一点,也不确定我是否误解了它。

谁能澄清一下吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-06-20 20:31:19

据我所知,同步原语根本不会影响缓存的一致性。缓存是法语,因为隐藏,它不应该是可见的用户。缓存一致性协议应该在没有程序员参与的情况下工作。

同步原语将影响内存排序,这是很好定义的,并且通过处理器的ISA对用户是可见的。

有详细信息的一个很好的来源是来自计算机体系结构集合的综合讲座的记忆一致性和缓存一致性初探

编辑:澄清您的疑问

维基百科的说法略有错误。我认为混淆可能来自于术语内存的一致性和缓存的一致性。他们的意思不一样。

C中的volatile关键字意味着变量总是从内存中读取(相对于寄存器),编译器不会重新排序加载/存储。这并不意味着硬件不会重新排序负载/存储。这是一个内存一致性问题。当使用较弱的一致性模型时,程序员需要使用同步原语来强制执行特定的排序。这与缓存一致性不同。例如,如果线程1修改了位置A,那么在此事件线程2加载位置A之后,它将收到一个更新的(一致)值。如果使用缓存一致性,这应该会自动发生。内存排序是一个不同的问题。您可以查看著名的论文共享内存一致性模型:教程获得更多信息。最著名的例子之一是德克尔算法,它需要顺序一致性或同步原语。

EDIT2:我想澄清一件事。虽然我的缓存一致性示例是正确的,但在某些情况下,内存一致性可能与其重叠。当存储在处理器中执行,但延迟进入缓存时(它们位于存储队列/缓冲区中)。由于处理器的缓存尚未收到更新的值,其他缓存也不会。这可能看起来像是缓存一致性问题,但实际上它不是,实际上也是ISA内存一致性模型的一部分。在这种情况下,可以使用同步原语将存储队列刷新到缓存。考虑到这一点,您用粗体突出显示的维基百科文本是正确的,但另一个文本仍然略有错误:关键字易失性不能保证有一个内存屏障来强制缓存一致性。应该这样说:关键字易失性不能保证一个内存屏障来执行内存一致性

票数 11
EN

Stack Overflow用户

发布于 2019-01-27 08:34:39

简短的回答:缓存一致性大部分时间起作用,但并不总是起作用。您仍然可以读取陈旧的数据。如果你不想冒险,那就用一个记忆屏障

很长的答案: CPU核心不再直接连接到主存。所有的负载和存储都必须经过缓存。每个CPU都有自己的私有缓存这一事实引发了新的问题。如果多个CPU正在访问相同的内存,那么仍然必须确保两个处理器在任何时候都看到相同的内存内容。如果缓存行在一个处理器上是脏的(也就是说,它还没有被写回主内存),并且第二个处理器试图读取相同的内存位置,那么读取操作就不能直接输出到主存储器。。相反,需要第一个处理器的证书的内容。现在的问题是,何时必须发生缓存线传输?这个问题很容易回答:当一个处理器需要一个缓存行时,它在另一个处理器的缓存中是脏的,用于读或写。但是,处理器如何确定缓存行在另一个处理器的缓存中是否是脏的?假设它仅仅因为缓存行由另一个处理器加载就不是最优的(充其量)。通常,大多数内存访问都是读访问,而产生的缓存行并不脏。这里有缓存一致性协议。CPU通过MESI或其他缓存一致性协议在缓存中维护数据一致性。

在缓存一致性到位的情况下,我们不应该总是看到这个最新值,即使它是由另一个CPU修改的?毕竟,这是缓存一致性协议的全部目的。通常在修改证书时,对应的CPU会向所有其他CPU发送“失效证书”请求,结果是CPU可以立即向无效请求发送确认,但将证书的实际失效推迟到稍后的时间点。这是通过无效队列完成的。现在,如果我们足够幸运地读取这个短窗口内的背线(在CPU之间确认无效请求,而实际上使证书无效),那么我们可以读取一个陈旧的值。为什么CPU会做这么可怕的事。简单的答案是性能。因此,让我们看看无效队列可以提高性能的不同场景。

  • 场景1:CPU1接收来自CPU2的无效请求。CPU1也有很多存储和加载排队等待缓存。这意味着所请求的证书的失效需要时间,而CPU2则会被延迟,等待确认。
  • 场景2:CPU1在短时间内接收大量无效请求。现在,CPU1需要时间才能使所有单身汉失效。

将条目放入无效队列本质上是CPU在发送有关该缓存行的任何MESI协议消息之前处理该条目的承诺。因此,即使对单个变量进行简单读取,无效队列也可能看不到最新的值。

现在,热衷于阅读的读者可能会想,当CPU想要读取一个记录线时,它可以先扫描失效队列,然后再从缓存中读取。这样就可以避免这个问题了。然而,CPU和失效队列被物理地放置在缓存的对立面,这限制了CPU直接访问失效队列。(一个CPU缓存的失效队列通过系统总线由来自其他CPU的缓存一致性消息填充。因此,在缓存和系统总线之间放置失效队列是有意义的)。因此,为了实际查看任何共享变量的最新值,我们应该清空无效队列。通常,读记忆屏障就能做到这一点。

我刚才谈到了失效队列和读取内存屏障。1是一个很好的参考,以了解读写内存障碍的必要性和MESI高速缓存一致性协议的细节。

1

票数 15
EN

Stack Overflow用户

发布于 2015-06-20 20:09:57

维基百科告诉你的是,volatile并不意味着要插入一个内存屏障来执行缓存一致性。然而,适当的内存屏障将强制多个CPU核之间的内存访问是一致的,您可能会发现阅读订单文档很有帮助。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30958375

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档