Concurrency x86 CMPXCHG是原子的吗?如果是,为什么需要锁?

Concurrency x86 CMPXCHG是原子的吗?如果是,为什么需要锁?,concurrency,x86,atomicity,lock-free,compare-and-swap,Concurrency,X86,Atomicity,Lock Free,Compare And Swap,警察说 此指令可与锁前缀一起使用,以允许以原子方式执行指令 我的问题是 CMPXCHG能否使用内存地址进行操作?从文档中可以看出,它似乎不起作用,但有人能确认它只适用于寄存器中的实际值,而不适用于内存地址吗 如果CMPXCHG不是原子的,并且必须通过LOCK CMPXCHG(带有LOCK前缀)实现高级语言级CAS,那么引入这种指令的目的是什么 (我是从高级语言的角度提出这个问题的。也就是说,如果无锁算法必须在x86平台上转换为锁CMPXCHG,那么它的前缀仍然是lock。这意味着无锁算法并不

警察说

此指令可与
前缀一起使用,以允许以原子方式执行指令

我的问题是

  • CMPXCHG
    能否使用内存地址进行操作?从文档中可以看出,它似乎不起作用,但有人能确认它只适用于寄存器中的实际值,而不适用于内存地址吗

  • 如果
    CMPXCHG
    不是原子的,并且必须通过
    LOCK CMPXCHG
    (带有
    LOCK
    前缀)实现高级语言级CAS,那么引入这种指令的目的是什么


  • (我是从高级语言的角度提出这个问题的。也就是说,如果无锁算法必须在x86平台上转换为锁CMPXCHG,那么它的前缀仍然是lock。这意味着无锁算法并不比那些精心编写的同步锁/互斥锁(至少在x86上)算法更好。)。这似乎也使得裸CMPXCHG指令毫无意义,因为我想引入它的主要目的是支持这种无锁操作。)

    锁前缀是锁定当前命令的内存访问,以便CPU管道中的其他命令不能同时访问内存。使用LOCK前缀,命令的执行不会因为同时执行的其他命令的内存访问而被CPU管道中的其他命令中断。 英特尔手册上说:

    锁定前缀只能在以下指令前加上 而且只适用于目的地 操作数是内存操作数:ADD、ADC和、BTC、BTR、BTS、CMPXCHG、, CMPXCH8B、CMPXCHG16B、DEC、INC、NEG、NOT或SBB、SUB、XOR、XADD和 XCHG。如果锁定前缀与这些指令之一一起使用,以及 源操作数是内存操作数,是未定义的操作码异常 (#UD)可以生成


    您将高级锁与名为
    LOCK
    的低级CPU功能混为一谈

    无锁算法试图避免的高级锁可以保护执行可能需要任意时间的任意代码片段,因此,这些锁必须将线程置于等待状态,直到锁可用为止,这是一项代价高昂的操作,例如,意味着维护等待线程的队列

    这与CPU
    LOCK
    prefix功能完全不同,后者仅保护一条指令,因此可能仅在该条指令的持续时间内保留其他线程。由于这是由CPU本身实现的,因此不需要额外的软件工作


    因此,开发无锁算法的挑战并不是完全取消同步,它归结起来是将代码的关键部分简化为单个原子操作,这将由CPU本身提供。

    您真正想问的似乎是:

    为什么带内存操作数的
    cmpxchg
    lock
    前缀不是隐式的(从386开始)

    简单的答案(其他人已经给出)就是英特尔就是这样设计的。但这引出了一个问题:

    英特尔为什么这么做?是否存在不带锁的
    cmpxchg
    用例

    在单CPU系统上,
    cmpxchg
    相对于其他线程或运行在同一CPU核心上的任何其他代码而言是原子的。(但不适用于“系统”观察者,如内存映射的I/O设备,或对普通内存进行DMA读取的设备,因此
    lock cmpxchg
    即使在单处理器CPU设计上也是相关的)

    <强>上下文切换只能在中断发生,中断发生在指令之前或之后,而不是在中间。在同一CPU上运行的任何代码将看到

    cmpxchg
    已完全执行或根本未执行



    例如,Linux内核通常使用SMP支持进行编译,因此它对原子CA使用
    lock cmpxchg
    。但是,当在单处理器系统上启动时,它会将
    lock
    前缀修补到
    nop
    内联代码的任何地方,因为
    nop
    cmpxchg
    运行速度比
    lock cmpxchg
    快得多。有关更多信息,请参阅此。它甚至可以在热插拔第二个CPU之前修补回
    锁定
    前缀

    阅读有关单处理器系统上单指令原子性的更多信息,以及关于Can
    num++
    be-atomic for
    int-num
    。有关原子性如何真正工作/如何实现的详细信息,请参阅,如
    lock cmpxchg



    (同样的推理也适用于
    cmpxchg8b
    /
    cmpxchg16b
    xadd
    ,它们通常仅用于同步/原子操作,而不是使单线程代码运行得更快。当然,像
    add[mem],reg
    这样的内存目标指令在
    锁添加[mem]之外很有用,reg
    case。)

    显然,您可以使用内存地址,这就是重点。第一个操作数的类型是r/m,所以就这样。如果指令本身不存在,你怎么能在指令前面加上
    lock
    。如果希望指令是原子指令,可以使用LOCK作为前缀。那么没有锁前缀的CMPXCHG是原子的还是非原子的?不,但在你的问题2中,你似乎在问为什么“没有锁的CMPXCHG”存在,这有点奇怪,因为没有部分组合就不可能存在-如果这不是你的意思,那么你能澄清一下吗?@harold我是从高级语言的角度问的。也就是说,如果无锁算法必须在x86平台上转换为lock CMPXCHG,那么它的前缀仍然是lock。这意味着无锁算法并不比精心编写的同步锁/murex(至少在x86上)更好。这似乎使CMPXCHG系统