虚假共享且不稳定

Alm*_*zak 5 java caching false-sharing

大家好,我最近发现了 Java 8 中引入的一个注释,称为Contished。从这个邮件列表中,我了解了什么是错误共享以及注释如何允许对象或字段分配整个缓存行。

经过一番研究,我发现如果两个核心存储相同的缓存行,并且其中一个核心对其进行修改,那么第二个核心必须从主内存中重新读取整行。https://en.wikipedia.org/wiki/MESI_protocol。但我仍然不清楚为什么硬件会强制 CPU 重新读取它。我的意思是,这就是为什么我们在 Java 中有一个 volatile 关键字,对吗?如果变量被声明为易失性,那么线程将从缓存中跳过该变量,并始终从主内存中读取/写入它。如果硬件强制 cpu 在每次写入后重新读取缓存行,那么在多线程应用程序中如何可能出现数据不一致?
提前致谢

pve*_*jer 2

After some research I found that if two cores store the same cache line and 
one of them modify it then the second one has to reread entire line from main memory. https://en.wikipedia.org/wiki/MESI_protocol.
Run Code Online (Sandbox Code Playgroud)

这是不正确的。缓存是事实来源,因为缓存(至少在 X86 上)始终是一致的。因此理论上,缓存行永远不需要从主存中读取;它始终可以从 CPU 缓存之一提供服务。如果不同的 CPU 缓存需要缓存行,它只需从其他缓存读取值即可。使用 MESI,当缓存行处于修改状态并且不同的 CPU 想要读取它时,可能会发生缓存行被刷新到主内存的情况;但除此之外不需要与主存储器进行通信。这是因为MESI不支持脏共享;MOESI 解决了这个问题。

 But it still unclear for me why hardware forces CPU to reread it. 
 I mean that is why we do have a volatile keyword in Java right ? 
Run Code Online (Sandbox Code Playgroud)

X86 上的缓存始终是一致的。为此不需要特殊的 CPU 指令;这是开箱即用的行为。因此,不可能发生这样的情况:例如,值 A=1 被写入某个缓存行,而稍后的读取仍然看到旧值 A=0。

 If variable is declared as volatile then threads will skip this variable 
 from cache and always read/write it from/to main memory. 
 If hardware forces cpu to reread cache lines after every write then how data inconsistency is possible in multi threaded applications?
Run Code Online (Sandbox Code Playgroud)

这是不正确的。缓存是事实的来源;没有“从主存储器强制读取”。有一些特殊指令可以绕过 CPU 缓存,称为非临时加载和存储,但它们与本讨论无关。

易失性的目的是确保保留相对于其他加载和存储到不同地址的顺序,并且存储对其他线程可见。

如有虚假分享;如果CPU修改同一高速缓存行的不同部分,并且一个CPU需要写入而另一个CPU刚刚写入它,则一旦写入命中,第一个CPU需要使用RFO(请求所有权)使另一个CPU上的高速缓存行无效linefillbuffer,并且在该 RFO 被确认之前无法继续写入。但是,一旦其他 CPU 想要写入该缓存行,它就需要发送 RFO 并等待确认。

因此,不同 CPU 之间会产生大量缓存一致性流量……不断争夺同一缓存行。如果运气不好,CPU 无法执行无序指令,因此即使您的 CPU 利用率为 100%,CPU 也将大部分处于空闲状态。