缓存一致性协议如何实现原子性?

use*_*112 6 cpu x86 assembly multithreading atomic

我理解通过依赖缓存一致性协议(MESI/MESIF)xsub(),可以在不使用LOCK前缀的操作上保证原子性.

1)缓存一致性协议如何做到这一点?

它让我想知道缓存一致性协议是否可以强制执行原子性,为什么我们需要特殊的原子类型/指令等?

2)如果MOSI跨多核系统实现原子指令那么目的是LOCK什么?遗产?

3)如果MOSI实现原子指令并且MOSI用于所有指令 - 那么为什么原子指令成本太高?当然,性能应该与普通指令相同.

Ros*_*dge 6

原子性和内存排序

对于原子操作,它必须在任何观察者看来都是一个不可分割的操作。该观察者可以是任何可以看到操作效果的东西,无论是执行操作的线程、同一处理器上的不同线程、不同处理器上的线程,还是系统中的某个组件或设备。无法看到操作效果的观察者,无论是同一个线程、不同的线程还是设备,都不会影响操作是否是原子的。

(请注意,处理器是指英特尔文档中所谓的逻辑处理器。具有两个 CPU 插槽的系统,每个插槽都装有一个四核 CPU,每个内核有两个逻辑处理器,总共有 16 个处理器。)

一个相关但不同的概念是内存排序。如果内存访问在观察者看来是按照它们在程序中出现的顺序发生的,那么它们只是顺序一致的。当观察者与执行操作的线程相同时,此保证始终适用。其他更有限的内存排序保证是可能的。强但顺序不一致的排序可能保证多种操作相对于彼此排序,但不是全部排序。弱内存排序不能保证其他线程的访问方式。

编译器和原子性

当您用 C 或其他一些高级语言编写程序时,某些操作可能看起来是原子的且按顺序排序,但编译器通常仅在从执行这些操作的同一线程中查看时才能保证这一点。但是,从编译器的角度来看,任何在线程被异步中断时运行的代码都会发生在不同的执行线程中,即使该代码运行在同一个操作系统线程中。这意味着在信号处理程序或结构化异常处理程序中运行的代码不能保证看到在同一线程中的处理程序外部执行的操作是原子的或顺序一致的。

由于有限的一般保证,编译器可以自由地做一些事情,比如使用多个汇编指令实现看起来是原子的操作,使它们在其他观察者看来是非原子的。编译器还可以重新排序内存访问,甚至完全删除明显冗余的访问。它可以在单个不间断线程的情况下做任何它想做的优化,程序仍然表现得好像它在按程序顺序执行所有这些操作。

在多线程情况下,或者信号或异常处理程序存在的情况下,有必要采取特殊步骤来通知编译器您需要在哪里提供更广泛的原子性和内存排序保证。这就是特殊原子类型和函数的目的。即使 CPU 保证每条指令都是原子的并且每个内存访问与所有其他线程顺序一致,编译器也不会。

Intel CPU 和原子性

Intel CPU 使编译器很容易提供这些保证。除了一些奇怪的情况,指令是不可中断的。任何导致指令执行被中断的事件要么在指令完全完成后发生,要么允许指令恢复,就好像它从未被执行过一样。这意味着在机器代码级别,每个操作都是原子的,并且每个内存操作都是顺序一致的,就像在同一处理器上运行的代码一样。在单处理器的情况下,不需要做任何事情来提供这些保证,除非它们需要对处理器以外的设备可见。在那种情况下LOCK必须使用前缀与未缓存的内存区域相结合,以保证读/修改/写指令是原子的,并且内存访问顺序与其他设备一致。

在访问缓存内存的多处理器情况下,缓存一致性协议提供了大多数指令的原子性和强内存排序的保证,但不是顺序一致的排序。执行此操作的确切机制并不重要,只是提供了保证。任何只访问单个内存位置的指令对其他处理器来说都是原子的。这里的顺序保证太长了,英特尔使用 16 个要点来描述它们,但它们显然是 C 和 C++ 提供的获取和释放内存顺序的保证的超集。当指定了该级别的内存排序时,C/C++ 原子操作可以使用普通的未锁定指令。

当您需要比缓存一致性协议提供的更强大的保证时,就需要LOCK前缀,以及那些LOCK隐含前缀的指令。如果你需要你的读/修改/写指令是原子的,你需要使用LOCK前缀。如果您需要顺序一致的排序,则需要使用LOCK前缀。

LOCK前缀就是原子操作的成本高得来的。它使处理器等待所有先前的加载和存储操作完成。即使在访问缓存内存时,LOCK前缀完全在缓存中处理而没有断言 LOCK#,处理器仍然需要等待以确保操作与其他处理器顺序一致。

概括

因此,总而言之,您的问题的答案是:

  1. 从其他处理器来看,缓存一致性协议只能强制某些机器代码指令的原子性。它不能确保编译器为您想要原子化的操作生成单个指令。它也不能保证该指令对于系统上的非处理器设备似乎是原子的。
  2. LOCK前缀上的机器代码指令使用的
    • 执行多个内存访问并且需要对其他处理器看起来是原子的
    • 需要与其他处理器顺序一致
    • 需要与其他非处理器设备保持原子和/或顺序一致。
  3. 如果可以在不使用LOCK前缀的情况下获得必要的原子性和内存排序保证,则使用的指令与普通指令相同,因此成本相同。在LOCK需要前缀来提供必要保证的情况下,指令的成本变得比普通指令高得多。


Jes*_*ter 5

xsubx86中没有指令,但有一个xadd;)

你应该阅读有关的部分LOCK前缀指令集,以及部分8.1 LOCKED原子操作软件开发人员手册卷3A:系统编程指南,第1部分.

单CPU指的是单核时下,有自己的缓存.当您有多个内核用于多个内核(物理上位于相同或不同的cpu芯片中)时,它们会使用一些缓存一致性协议.在这种情况下MESI,执行原子指令的核心将首先确保它拥有包含操作数的高速缓存行并对其进行标记modified,并另外将其锁定.如果另一个核心需要缓存行,它将执行读取操作,所有者核心将监听并延迟答案,直到原子操作完成.

在单CPU单核系统上,大多数指令在线程方面都是原子的,除了使用REP前缀的字符串指令,因为调度中断因此上下文切换只发生在指令边界上.然而,硬件设备可以观察到非原子行为.