Multithreading x86上的两个后续CPU存储是否刷新到缓存中,以保持顺序?

Multithreading x86上的两个后续CPU存储是否刷新到缓存中,以保持顺序?,multithreading,x86,cpu,cpu-cache,Multithreading,X86,Cpu,Cpu Cache,假设有两个线程分别在x86 CPU0和CPU1上运行。在CPU0上运行的线程执行以下命令: A=1 B=1 包含最初由CPU1拥有的A和包含由CPU0拥有的B的缓存线 我有两个问题: 如果我理解正确,这两个存储将被放入CPU的存储缓冲区。但是,对于第一个存储A=1必须使CPU1的缓存无效,而第二个存储B=1可以立即刷新,因为CPU0拥有包含它的缓存线。我知道x86CPU尊重商店订单。这是否意味着B=1不会在A=1之前写入缓存 假设在CPU1中执行以下命令: 而(B=0) 打印 仅在CPU1中的

假设有两个线程分别在x86 CPU0和CPU1上运行。在CPU0上运行的线程执行以下命令:

A=1
B=1
包含最初由CPU1拥有的A和包含由CPU0拥有的B的缓存线

我有两个问题:

  • 如果我理解正确,这两个存储将被放入CPU的存储缓冲区。但是,对于第一个存储
    A=1
    必须使CPU1的缓存无效,而第二个存储
    B=1
    可以立即刷新,因为CPU0拥有包含它的缓存线。我知道x86CPU尊重商店订单。这是否意味着
    B=1
    不会在
    A=1
    之前写入缓存

  • 假设在CPU1中执行以下命令:

  • 而(B=0)
    打印

    仅在CPU1中的
    while
    print
    命令之间添加lfence,而不在CPU0中的
    a=1
    B=1
    之间添加sfence,这样就可以在x86上始终打印出1了吗

    while (B=0);
    lfence
    print A
    

    在x86中,所有处理器都以相同的顺序观察单个处理器的写入。在您的示例中,或者在x86上的任何普通程序中,都不需要围栏。您的程序:

    while(B==0);  // wait for B == 1 to become globally observable
    print A;      // now, A will always be 1 here
    
    缓存中发生的事情是特定于模型的。缓存中可能会出现各种各样的技巧和推测行为,但可观察到的行为始终遵循规则


    请参阅《英特尔系统编程指南》第3卷第8.2.2节。有关内存排序的详细信息。

    即使x86保证了这一点,为什么还要冒险呢?为什么不使用正确的屏障呢?Zan,如果CPU能保证这一点,那么它在很多地方都是有优势的。例如,自旋锁是在内核中不使用任何锁前缀的情况下实现的,因为它们负担得起。围栏不是这个问题的解决方案,否则,你需要使用一把合适的锁。第一个问题的答案是肯定的。第二个问题的答案是肯定的,但只在汇编程序中(不是在C/C++中)。正如正确地说的那样,
    LFENCE
    在x86上不需要它-它自动提供了获取一致性。请注意,x86CPU不能对
    加载
    和任何后续指令进行重新排序,但C/C++可以对其进行重新排序。在C++中,你使用获取一致性:<代码>外部STD::atomic B;<代码>
    while(B.load(std::memory\u order\u acquire)==0)
    std::cout除非B被标记为
    volatile
    否则编译器可以将
    while(B==0)
    转换为
    while(true)
    ,因为就编译器而言,没有任何东西可以改变该循环中B的值。例如,C/C++编译器可以通过高优化级别来实现这一点。