【问题标题】:Why do we even need cache coherence?为什么我们甚至需要缓存一致性?
【发布时间】:2021-11-30 04:30:36
【问题描述】:

在像 C 这样的语言中,从不同线程对同一内存位置的非同步读取和写入是未定义的行为。但是在 CPU 中,cache coherence says 表示,如果一个内核写入一个内存位置,然后另一个内核读取它,那么另一个内核必须读取写入的值。

如果上一层只是将其丢弃,为什么处理器需要费心暴露内存层次结构的连贯抽象?为什么不让缓存变得不连贯,并要求软件在要共享某些内容时发出特殊指令?

【问题讨论】:

  • 内存屏障和缓存一致性是不同的东西
  • if the next layer up 嗯,C 不一定是“下一层”,C 中未定义的行为 only 意味着没有要求 C 标准要求的程序的行为 - 可能有其他标准的要求,特定的 C 程序可能取决于特定的硬件和编译器行为。
  • softwareengineering.stackexchange.com 可能更适合这个 Q。
  • 假设 CPU A 设置缓存行的字节 0 和 CPU B 或多或少同时设置字节 15。如果没有缓存一致性,就无法解决这个问题。做两次操作总会有一场比赛。
  • @stark 说得好,语言确实说你可以在不干扰相邻内存位置的情况下以大于字节的任何粒度进行写入

标签: c cpu cpu-architecture cpu-cache


【解决方案1】:

C++11 所需的 acquirerelease 语义 std::mutex(以及其他语言中的等价物,以及像 pthread_mutex 这样的更早的东西)将非常昂贵地实现,如果你没有连贯的缓存。每次释放锁时都必须写回每条脏行,每次获得锁时驱逐每条干净的行,如果不能依靠硬件使您的存储可见,并使您的负载不从私有缓存中获取陈旧数据。

但是对于高速缓存一致性,acquire and release 只是排序该核心对其自己的私有高速缓存的访问,该高速缓存是与其他核心的 L1d 高速缓存相同的一致性域的一部分。所以它们是本地操作并且非常便宜,甚至不需要耗尽存储缓冲区。互斥体的成本只是它需要执行的原子 RMW 操作,当然,如果拥有互斥体的最后一个内核不是这个,则缓存未命中。

C11 和 C++11 分别添加了 stdatomic 和 std::atomic,这使得访问共享的_Atomic int 变量得到了很好的定义,因此高级语言不公开这一点是不正确的。假设可以在需要显式刷新/无效以使存储对其他内核可见的机器上实现,但这会非常慢。语言模型假定缓存一致,不提供范围的显式刷新,而是提供释放操作,使 每个 旧存储对其他线程可见,这些线程执行与该线程中的释放存储同步的获取加载。 (有关一些讨论,请参阅When to use volatile with multi threading?,尽管该答案主要是为了揭穿缓存可能具有陈旧数据的误解,这是由于编译器可以“缓存”非原子非寄存器中的可变值。)

事实上,一些关于 C++ atomic 的保证实际上被标准描述为向软件公开 HW 一致性保证,如“写-读一致性”等,以注释结尾:

http://eel.is/c++draft/intro.races#19

[ 注意:前面的四个一致性要求实际上不允许编译器将原子操作重新排序到单个对象,即使这两个操作都是宽松的负载。 这有效地使大多数硬件提供的缓存一致性保证可用于 C++ 原子操作。 — 结束说明

(早在 C11 和 C++11 之前,SMP 内核和一些用户空间多线程程序都是手动滚动原子操作,使用与 C11 和 C++11 最终以可移植方式公开的相同硬件支持。)


此外,正如 cmets 中所指出的,一致的缓存对于写入同一行的不同部分其他内核不相互踩踏是必不可少的。

ISO C11 保证char arr[16] 可以让一个线程写入arr[0],而另一个线程写入arr[1]。如果它们都在同一个缓存行中,并且存在两个冲突的脏副本,则只有一个可以“获胜”并被写回。 C++ memory model and race conditions on char arrays

ISO C 实际上要求char 与您可以写入的最小单位一样大,而不会干扰周围的字节。在几乎所有机器(不是早期的 Alpha 和一些 DSP)上,that's a single byte,即使一个字节存储可能需要一个额外的周期来提交到 L1d 缓存而不是一些非 x86 ISA 上的对齐字。

该语言直到 C11 才正式要求这样做,但这只是标准化了“每个人都知道”的唯一明智选择,即编译器和硬件已经如何工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-20
    • 1970-01-01
    • 2016-09-24
    • 1970-01-01
    • 2021-06-27
    • 2017-05-07
    相关资源
    最近更新 更多