当线程调度在不同的 CPU 核心上时,预期的内存语义(例如写入后读取)会发生什么情况?

use*_*123 5 multithreading operating-system cpu-architecture memory-barriers cpu-cache

单线程内的代码具有一定的内存保证,例如先读后写(即将一些值写入内存位置,然后读回它应该给出您写入的值)。

如果线程被重新安排在不同的 CPU 核心上执行,这样的内存保证会发生什么?假设一个线程将 10 写入内存位置 X,然后重新调度到不同的核心。该核心的 L1 缓存可能具有不同的 X 值(与之前在该核心上执行的另一个线程不同),因此现在读取 X 不会像线程期望的那样返回 10。当线程被调度到不同的核心上时,是否会发生一些 L1 缓存同步?

Joh*_*pin 4

在这种情况下,所需要的只是在进程开始在第二个处理器上执行之前,在第一个处理器上执行的写入变得全局可见。在 Intel 64 架构中,这是通过在代码中包含一个或多个具有内存栅栏语义的指令来实现的,操作系统使用这些指令将进程从一个内核传输到另一个内核。Linux 内核的一个例子:

/*
 * Make previous memory operations globally visible before
 * sending the IPI through x2apic wrmsr. We need a serializing instruction or
 * mfence for this.
 */
static inline void x2apic_wrmsr_fence(void)
{
    asm volatile("mfence" : : : "memory");
}
Run Code Online (Sandbox Code Playgroud)

这确保了在执行将启动在新核心上运行的线程的处理器间中断之前,来自原始核心的存储是全局可见的。

参考:《英特尔架构软件开发人员手册》(文档 325384-071,2019 年 10 月)第 3 卷第 8.2 和 8.3 节。