PAYATHON 2026

x86-64 中 MFENCE 完成后,其他核心稍后执行的 LOAD 必须读到新值吗?

数据小陈

如果题设中的“随后执行 LOAD”确实表示 T1 的 MFENCE 已完成,且 T2 的 LOAD X 此前尚未读取该位置,那么在普通、保持缓存一致性的 WB 内存上,没有其他写入的前提下,T2 必须读到 X = 1。T2 不需要再执行一次 MFENCE 才能看到这个值。

这里需要明确“执行”的含义。LOAD 实际读取内存的时刻,可能不同于指令退休或程序记录日志的时刻。仅凭后两者的时间顺序,不能直接得出题设中的前提。

MFENCE 的全局可见性意味着什么?

问题引用的 Intel 手册说明,MFENCE 会按要求对其前后的内存访问排序。手册同时指出,MFENCE 不会序列化整个指令流。对于 LOAD,“全局可见”表示将要装入目标寄存器的值已经确定。Intel 指令手册:MFENCE

在 x86-TSO 的抽象机器中,每个线程都有自己的 FIFO store buffer。STORE 可以先进入缓冲区,随后传播到共享内存;MFENCE 只有在本线程的 store buffer 为空时才能通过。其他线程读取某个地址时,如果没有可转发的本地写入,就从抽象的共享内存取值。x86-TSO 论文,第 3 节

将这些规则用于简化示例,可以得到:

STORE X = 1 传播到全局一致性域
    → T1 的 MFENCE 完成
    → T2 的 LOAD X 实际读取

在这一顺序下,如果没有后续写入,最后一步应当返回 1。这是上述模型在题设顺序下的直接推论。

“全局可见”也不要求把数据写回 DRAM,或主动把 1 填进每个核心的缓存。数据可以留在缓存层次中,一致性机制负责使后续读取获得正确的值。

为什么稍后退休的 LOAD 仍可能返回旧值?

“稍后退休”没有说明 LOAD 是什么时候取值的。例如,以下时间线与题设中的“稍后才开始读取”不同:

T2 的 LOAD X 提前执行,取得 0
T1 的 STORE X = 1 成为全局可见
T1 的 MFENCE 完成
T2 的 LOAD X 退休,提交先前取得的 0

这里的 LOAD 在写入全局可见之前已经读取。它稍后退休,并不会因此自动重新读取内存。

同理,源代码顺序、日志输出时间或缺少充分排序约束的计时结果,都不能直接代替实际内存访问顺序。处理器可能提前执行指令;最终允许保留哪些结果,还必须满足架构规定的内存顺序。

这并不意味着,真正发生在全局可见写入之后的读取仍可任意返回旧缓存值。要区分 LOAD 的取值发生在写入全局可见之前还是之后。

为什么第一组程序不能同时读到 0?

将原始示例对齐,并给两个 LOAD 的结果命名:

T1:                 T2:
STORE X = 1         STORE Y = 1
MFENCE              MFENCE
r1 = LOAD Y         r2 = LOAD X

假设 X、Y 初始为 0,之后各只有这一次写入。

两条 MFENCE 分别要求:

STORE X = 1 → r1 = LOAD Y
STORE Y = 1 → r2 = LOAD X

如果 r1 = 0,读取 Y 就必须排在 STORE Y = 1 全局可见之前;如果 r2 = 0,读取 X 也必须排在 STORE X = 1 全局可见之前。把这些约束连接起来:

STORE X = 1
    → LOAD Y
    → STORE Y = 1
    → LOAD X
    → STORE X = 1

这些约束形成了顺序环,因此两个结果不能同时为 0。证明依据的是内存顺序约束,不需要先测出两个核心各条指令的物理时间。

如何在程序中建立可观察的先后关系?

原问题已经明确假设时间顺序成立,因此回答该假设不需要额外同步。如果实际程序需要建立这种关系,可以发布一个标志,让读取线程根据标志继续执行:

# 初始值:X = 0,ready = 0

T1:
    STORE X = 1
    MFENCE
    STORE ready = 1

T2:
retry:
    r = LOAD ready
    if r == 0: goto retry
    value = LOAD X

在相同的普通 WB 内存前提下,T2 读到 ready = 1 后,再读取 X 必须得到 1。在这种发布模式中,x86 的 Store → Store 和 Load → Load 顺序已足以提供所需约束。示例保留 MFENCE,是为了标记原问题所关心的完成阶段。

如果用 C 或 C++ 实现,应使用语言规定的原子操作和同步机制,例如 release/acquire 发布标志。单独插入硬件屏障不能替代语言层面的并发规则。

适用前提

以上分析针对同一物理内存位置、正常一致性域内的普通 WB 内存访问,并假设访问具备所需的原子性,没有其他线程再次修改 X。MMIO、特殊内存类型、不一致的内存映射或非原子访问,需要另外分析。

跨线程的真实时间推理要区分实际先后关系是否已确定。题设明确给定该关系时,可以得出 LOAD X 返回 1;如果程序只有这几条指令,且没有建立先后关系,T2 仍可能在写入全局可见之前读到 0。

备注:内容仅供参考。