Windows 上的 *Single CPU*(多核)上的 C++ 多线程 "cache coherence" 是否存在问题?

Is there an issue with "cache coherence" on C++ multi-threading on a *Single CPU* (Multi-Core) on Windows?

(编辑:澄清一下:“缓存一致性”的问题是在没有使用原子变量的情况下。)

是否有可能(单个 CPU 案例:Windows 可以 运行 在 Intel / AMD / Arm CPU 之上),thread-1 [= core-1 上的 30=]s 存储一个 bool 变量(例如),它保留在 L1 缓存中,而 core-n 上的线程 2 运行s 使用该变量,它在另一个上查找内存中的副本?

代码示例(为了演示这个问题,假设 std::atomic_bool 只是一个普通的 bool):

#include <thread>
#include <atomic>
#include <chrono>

std::atomic_bool g_exit{ false }, g_exited{ false };

using namespace std::chrono_literals;

void fn()
{
    while (!g_exit.load(std::memory_order_relaxed))
    {
        // do something (lets say it takes 1-4s, repeatedly)
        std::this_thread::sleep_for(1s);
    }

    g_exited.store(true, std::memory_order_relaxed);
}

int main()
{
    std::thread wt(fn);
    wt.detach();

    // do something (lets say it took 2s)
    std::this_thread::sleep_for(2s);

    // Exit

    g_exit.store(true, std::memory_order_relaxed);

    for (int i = 0; i < 5; i++) { // Timeout: 5 seconds.
        std::this_thread::sleep_for(1s);
        if (g_exited.load(std::memory_order_relaxed)) {
            break;
        }
    }
}

CPU 缓存始终在我们 运行 C++ 线程跨越 1 的内核之间保持一致,无论它们是否在同一个包中(a multi-core CPU) and/or 分布在具有互连的套接字上。一旦写入线程的存储已执行并提交到缓存,就不可能加载过时值。作为这样做的一部分,它将向系统中的所有其他缓存发送一个无效请求。

其他线程总能最终看到您对 std::atomic 变量的更新,即使 mo_relaxed 也是如此。这就是重点; std::atomic 如果它对这个不起作用就没用了。

但是如果没有 std::atomic,你的代码会非常糟糕,https://electronics.stackexchange.com/questions/387181/mcu-programming-c-o2-optimization-breaks-while-loop/387478#387478 / 的一个经典示例 - 编译器可以假设没有其他线程正在写入它正在读取的 non-atomic var ,因此它可以将实际负载提升到循环之外并将其保存在 thread-private CPU register 中。所以它根本不是来自一致缓存的 re-reading。即 while(!exit_now){} 变为 if(!exit_now) while(1){} 普通 bool exit_now 全局。

(除了你的 sleep_for 调用可能会阻止优化。它可能没有声明为纯的,因为你不希望编译器优化对它的多次调用;时间是 side-effect . 所以编译器必须假设对它的调用可以修改全局变量,因此 re-read 内存中的全局变量(使用通过连贯缓存的正常加载指令)。


脚注 1:支持 std::thread 的 C++ 实现仅 运行 它跨同一一致性域中的内核。在几乎所有系统中,只有一个一致性域包含所有插槽中的所有内核,但节点之间具有 non-coherent 共享内存的巨大集群是可能的。

具有 ARM 微控制器内核共享内存但 与 ARM DSP 内核一致的嵌入式板也是如此。您不会 运行 在这两个内核上使用单个 OS,您也不会考虑在同一 C++ 程序的不同内核部分上使用代码 运行。

有关缓存一致性的更多详细信息,请参阅When to use volatile with multi threading?