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.
这是不正确的。缓存是事实的来源,因为缓存(至少在 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 ?
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?
这是不正确的。缓存是事实的来源;没有“从主存储器强制读取”。有一些特殊的指令可以绕过 CPU 缓存,称为非临时加载和存储,但它们与本次讨论无关。
volatile 的目的是确保保留相对于其他加载和存储到不同地址的顺序,并且存储对其他线程可见。
在虚假分享的情况下;如果 CPU 修改同一缓存线的不同部分,并且一个 CPU 需要写入,而另一个 CPU 刚刚写入,那么一旦写入命中,第一个 CPU 需要使用 RFO(所有权请求)使另一个 CPU 上的缓存线无效linefillbuffer 并且在此 RFO 被确认之前无法继续写入。但是一旦其他 CPU 想要写入该缓存线,它就需要发送一个 RFO 并等待确认。
因此,您会在不同的 CPU 之间获得大量缓存一致性流量……不断争夺相同的缓存线。如果运气不好,CPU 不会执行乱序指令,因此即使 CPU 利用率达到 100%,CPU 也基本上处于空闲状态。