原子操作如何在硬件级别实现?

Ale*_*ene 36 language-agnostic x86 smp atomicity

我在汇编语言级别获得了指令集架构,提供了比较和交换以及类似的操作.但是,我不明白芯片是如何提供这些保证的.

正如我想象的那样,指令的执行必须

  1. 从内存中获取值
  2. 比较价值
  3. 根据比较,可能在内存中存储另一个值

是什么阻止了另一个核心在第一次获取内存地址之后但在设置新值之前访问内存地址?内存控制器是否管理这个?

编辑:如果x86实现是秘密的,我会很高兴听到任何处理器家族如何实现它.

Mac*_*ser 28

这是一篇关于so​​ftware.intel.com 的文章,它对用户级锁定有所了解:

用户级锁涉及利用处理器的原子指令以原子方式更新存储空间.原子指令涉及在指令上使用锁定前缀并将目标操作数分配给存储器地址.以下指令可以在当前Intel处理器上以锁定前缀原子运行:ADD,ADC,AND,BTC,BTR,BTS,CMPXCHG,CMPXCH8B,DEC,INC,NEG,NOT,OR,SBB,SUB,XOR,XADD和XCHG.[...]在大多数指令中,必须显式使用锁定前缀,但xchg指令除外,如果指令涉及内存地址,则隐含锁定前缀.

在英特尔486处理器的时代,锁定前缀用于断言总线上的锁定以及性能的大幅提升.从Intel Pentium Pro架构开始,总线锁转换为缓存锁.如果锁定位于不可缓存的内存中,或者如果锁定超出高速缓存行边界分割高速缓存行,则在最现代的体系结构中仍然会在总线上声明锁定.这两种情况都不太可能,因此大多数锁前缀将转换为缓存锁,这种方法要便宜得多.

那么是什么阻止了另一个核心访问内存地址?该高速缓存一致性协议已经管理的高速缓存行的访问权限.因此,如果核心具有(临时)对高速缓存行的独占访问权限,则没有其他核心可以访问该高速缓存行.要访问该缓存行,其他核心必须首先获取访问权限,获取这些权限的协议涉及当前所有者.实际上,缓存一致性协议可以防止其他内核静默访问缓存行.

如果锁定的访问没有绑定到单个缓存行,则事情变得更加复杂.有各种令人讨厌的角落案例,例如对页面边界的锁定访问等.英特尔不会告诉细节,他们可能会使用各种技巧来加快锁定速度.


rah*_*hul 6

缓存一致性协议本身不足以实现原子操作。假设您想实现原子增量。以下是涉及的步骤

  1. 将值从缓存加载到寄存器中
  2. 增加加载到寄存器中的值
  3. 将更新后的值存储回缓存

因此,为了以原子方式实现上述 3 条指令,我们应该首先获得对包含所需值的缓存行的独占访问权。一旦获得独占访问权限,在“存储”操作完成之前,我们不应该放弃对此缓存行的独占访问权限。这意味着执行原子指令的 CPU 不应同时响应该高速缓存行的任何高速缓存一致性协议消息。虽然问题在于如何实现的细节,但至少它给了我们一个心理模型

下面是 linus torvalds 提到的有关原子指令的内容

原子指令绕过存储缓冲区,或者至少它们的行为就像它们这样做一样 - 它们可能实际上使用存储缓冲区,但它们在加载之前刷新它和指令管道,并等待它耗尽,并且在缓存行上有锁它们作为加载的一部分,并作为存储的一部分进行释放 - 所有这些都是为了确保缓存行不会在中间消失,并且在此过程中没有其他人可以看到存储缓冲区内容。