c++ - 我可以在多核 x86 CPU 上强制缓存一致性吗?

标签 c++ multithreading x86 multicore cpu-cache

另一周,我写了一个小线程类和一个单向消息管道来允许线程之间的通信(显然,每个线程有两个管道,用于双向通信)。在我的 Athlon 64 X2 上一切正常,但我想知道如果两个线程都在查看同一个变量并且每个内核上该变量的本地缓存值不同步,我是否会遇到任何问题。

我知道 volatile 关键字会强制变量从内存中刷新,但是在多核 x86 处理器上是否有办法强制所有内核的缓存同步?这是我需要担心的事情吗,或者 volatile 和正确使用轻量级锁定机制(我使用 _InterlockedExchange 来设置我的 volatile 管道变量)会处理我想要编写“无锁”的所有情况多核 x86 CPU 的代码?

我已经知道并使用了关键部分、互斥体、事件等。我主要想知道是否有我不知道的 x86 内在函数,或者可以用来强制缓存一致性。

最佳答案

volatile 仅强制您的代码重新读取该值,它无法控制从何处读取该值。如果你的代码最近读取了这个值,那么它可能会在缓存中,在这种情况下,volatile 会强制它从缓存中重新读取,而不是从内存中读取。

x86 中没有很多缓存一致性指令。有像 prefetchnta 这样的预取指令,但这不会影响内存排序语义。它过去是通过将值带入 L1 缓存而不污染 L2 来实现的,但是对于具有大型共享包含 L3 缓存的现代英特尔设计来说,事情变得更加复杂。

x86 CPU 使用 MESI protocol 的变体(英特尔的 MESIF,AMD 的 MOESI)保持它们的缓存相互一致(包括不同内核的私有(private) L1 缓存)。想要写入缓存行的核心必须强制其他核心使其拷贝无效,然后才能将自己的拷贝从共享状态更改为修改状态。


您不需要任何栅栏指令(如 MFENCE)来在一个线程中生成数据并在 x86 上的另一个线程中使用它,因为 x86 加载/存储有 acquire/release semantics内置。您确实需要 MFENCE (完全障碍)来获得顺序一致性。 (此答案的先前版本表明需要 clflush,这是不正确的)。

你确实需要阻止compile-time reordering ,因为 C++ 的内存模型是弱序的。 volatile 是一种旧的、糟糕的方法; C++11 std::atomic 是编写无锁代码的更好方法。

关于c++ - 我可以在多核 x86 CPU 上强制缓存一致性吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/558848/

相关文章:

c - 为什么 GDB 和不同的汇编程序给出不同的错误 jmp 地址?

c - 编码 CALL 指令以调用函数

c++ - read_some() 工作但很慢, read() 没有

c++ - 混淆三种引用形式

c++ - 如何避免在派生类中提前销毁?

java - 如果我知道线程名称,如何检查线程在 tomcat 中是否仍然存在?

c - 忽略系统调用

c++ - 将整数转换为 char* C++

c# - P/Invoke Interop Assistant - 是否像导入 dll 的 header 一样简单?

java - 多线程程序中出现意外结果