memory - 为什么加载不能绕过写入缓冲区中同一内核上的另一个线程写入的值?

标签 memory cpu cpu-architecture instructions memory-model

如果 CPU 核心使用写缓冲区,则加载可以绕过最近的存储到写缓冲区中的引用位置,而无需等到它出现在缓存中。但是,正如 A Primer on Memory Consistency and Coherence 中所写的那样,如果 CPU 支持 TSO 内存模型,则

... multithreading introduces a subtle write buffer issue for TSO. TSO write buffers are logically private to each thread context (virtual core). Thus, on a multithreaded core, one thread context should never bypass from the write buffer of another thread context. This logical separation can be implemented with per-thread-context write buffers or, more commonly, by using a shared write buffer with entries tagged by thread-context identifiers that permit bypassing only when tags match.

我无法理解这种限制的必要性。当允许某些线程绕过同一内核上另一个线程写入的写入缓冲区条目导致违反 TSO 内存模型时,您能否给我一个示例?

最佳答案

TSO 与顺序一致性 (SC) 有何不同的经典示例是:

(这里是示例 2.4 - http://www.cs.cmu.edu/~410-f10/doc/Intel_Reordering_318147.pdf)

  thread 0     |     thread 1
---------------------------------
write 1-->[x]  |   write 1-->[y]    
a = read [x]   |   b = read  [y]    
c = read [y]   |   d = read  [x]    

两个地址最初都存储 0。问题是:c=d=0 会是一个有效的结果吗?我们知道 a 和 b 必须转发它们之前的存储,因为它们与本地存储的地址匹配,并且可能会从本地线程存储缓冲区转发。但是,c 和 d 可能不会跨上下文转发,因此它们可能仍显示旧值。

这里有趣的陷阱是,由于每个线程都观察两个存储,并转发本地存储,a=1,c=0 的结果意味着 t0 看到 [x] 的存储首先发生。 b=1,d=0 的结果意味着 t1 看到 [y] 的存储首先发生。这是由于存储缓冲区转发导致的可能结果这一事实会破坏顺序一致性,因为它要求所有上下文都同意相同的存储全局顺序。相反,x86 解决了允许这种情况的较弱的 TSO 模型。

全局转发存储实际上是不可能的,因为缓冲存储不一定被提交,这意味着它们甚至可能处于分支预测错误的错误路径中。本地转发很好,因为刷新也会消除从它们转发的所有负载,但在多个上下文中你没有。 我还看到过尝试在核心外部全局缓冲存储的工作,但由于延迟和带宽,这不是很实用。为了进一步阅读,这里有一篇可能相关的最新论文 - http://ieeexplore.ieee.org/abstract/document/7783736/

关于memory - 为什么加载不能绕过写入缓冲区中同一内核上的另一个线程写入的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42847530/

相关文章:

java - 如何在 Mac 中获取 Tomcat 的堆转储和线程转储

x86 - 在特定的CPU环中不能发出哪些指令

assembly - 堆、堆栈和数据段是否在同一个汇编程序中?

python - 在不同的机器上加载 pickle 的对象

assembly - 现代 CPU 与 GPU 可以完成多少级流水线?

memory - 逻辑地址的目的?

arrays - Go 如何保证元素指针对数组和 slice 有效?

Java 进程内存远大于指定的限制

java - 为什么我的线程程序只使用一个 CPU?

c++ - 0和128的区别