比较和交换C语言中的机器代码

比较和交换C语言中的机器代码,c,multithreading,x86,compare-and-swap,C,Multithreading,X86,Compare And Swap,如何用C编写一个函数,使用嵌入式机器代码(假设x86体系结构)对整数值进行原子比较和交换?如果它只为i7处理器编写,那么它还能更具体吗 翻译是否起到了内存隔离的作用,还是仅仅确保了比较和交换中包含的内存位置上的排序关系?与内存围栏相比,它的成本有多高 谢谢。最简单的方法可能是使用类似的工具。它看起来像一个函数,但实际上是编译器中的一个特例,可以归结为一个单机操作。在MSVC x86内部版本中,它也可以作为读/写隔离,但在其他平台上不一定如此。(例如,在PowerPC上,您需要显式地发出一个限制来

如何用C编写一个函数,使用嵌入式机器代码(假设x86体系结构)对整数值进行原子比较和交换?如果它只为i7处理器编写,那么它还能更具体吗

翻译是否起到了内存隔离的作用,还是仅仅确保了比较和交换中包含的内存位置上的排序关系?与内存围栏相比,它的成本有多高


谢谢。

最简单的方法可能是使用类似的工具。它看起来像一个函数,但实际上是编译器中的一个特例,可以归结为一个单机操作。在MSVC x86内部版本中,它也可以作为读/写隔离,但在其他平台上不一定如此。(例如,在PowerPC上,您需要显式地发出一个限制来重新排序内存。)


一般来说,在许多常见系统上,比较和交换操作通常只对其所接触的一个地址强制执行原子事务。其他内存访问可以重新排序,并且在多核系统中,除了您交换的内存地址之外,其他内存地址在内核之间可能不一致

您可以将
CMPXCHG
指令与
LOCK
前缀一起用于原子执行

例如

这会将EAX寄存器中的值与EBX寄存器中存储的地址处的值进行比较,并将EDX寄存器中的值存储到该位置(如果相同),否则会将EBX寄存器中存储的地址处的值加载到EAX中


您需要使用486或更高版本才能使用此指令。

如果整数值大于64位,请使用IA32 x86下的cmpxchg8b 8字节比较和交换。 变量必须是8字节对齐的

Example:
      mov   eax, OldDataA           //load Old first 32 bits
      mov   edx, OldDataB           //load Old second 32 bits
      mov   ebx, NewDataA           //load first 32 bits
      mov   ecx, NewDataB           //load second 32 bits
      mov   edi, Destination        //load destination pointer
      lock cmpxchg8b qword ptr [edi]
      setz  al                      //if transfer is succesful the al is 1 else 0

如果原子处理器指令中省略了锁前缀,则不能保证跨多处理器环境的原子操作

在多处理器环境中,锁定信号确保处理器在断言信号时独占使用任何共享内存


如果没有锁定前缀,操作将保证不会被当前处理器/内核上的任何事件(中断)中断。

有趣的是,有些处理器不提供比较交换,而是提供一些其他指令(“加载链接”和“条件存储”)这可用于合成不幸命名的比较和交换(名称听起来应该类似于“比较交换”,但实际上应该称为“比较和存储”,因为它进行比较,如果值匹配则存储,并指示值是否匹配以及是否执行了存储)。这些指令无法综合比较交换语义(提供在比较失败时读取的值),但在某些情况下可以避免比较交换中出现的ABA问题。许多算法用“CAS”操作来描述,因为它们可以在两种类型的CPU上使用


“加载链接”指令告诉处理器读取内存位置,并以某种方式观察它是否可能被写入。“条件存储”指令指示处理器仅当自上次“加载链接”操作以来没有任何东西可以写入内存位置时,才写入内存位置。注意,决定可能是悲观的;例如,处理中断可能使“加载链接”/“条件存储”序列无效。同样,在多处理器系统中,LL/CS序列可能会因另一个CPU访问与被监视位置位于同一缓存线上的位置而失效,即使未触及被监视的实际位置。在典型的使用中,LL/C被紧密地结合在一起使用,并有一个重试循环,因此错误的失效可能会降低速度,但不会造成太多麻烦。

通常,您将一个值与一个内存位置进行比较和交换,您似乎在谈论两个更复杂的内存位置。这确实是你需要的吗?对不起,我指的是单个内存位置,我会澄清。谢谢你的回答!但是,在当前的任何多核系统上,甚至可以进行非内存围栏比较和交换吗?在这个问题上,一位用户声称,在x86体系结构上,唯一的比较和交换指令是CMPXCHG,它必须通过锁(作为内存围栏)进行保护,以使其原子化——这是唯一的方法。你知道这个说法是否正确吗?我认为对于x86来说,他是对的(我不是英特尔方面的专家)。但是还有其他具有其他语义的处理器。例如,PowerPC有一个不同的模型,它在地址上创建一个“保留”,然后有条件地存储。但这只能保证在那一个地方有围栏。在比较和交换之后,另一个核心可能会将先前的存储存储到不同的位置。此外,在该芯片上,“一致性并不能确保一个处理器的存储结果对所有其他处理器都立即可见。”也就是说,有两个内核,a和B。如果a和B都对地址0x100执行C&s操作,那么它们将同意执行该操作的顺序。B将首先看到A的值,然后看到B的值。但是,如果A对地址0x100执行普通的“0”写入,那么B将“1”写入0x100,然后它们都在地址0x200上执行C&S操作——之后它们都会在0x200处看到相同的值,但A可能仍然认为0x100包含“0”。事实上,A的写入可能会在B之后到达0x100,因此该值最终确实为0。非常感谢您的澄清!这就是我想知道的。我觉得你的第二段不完全正确,或者可能不清楚。通常,“锁定”操作/执行某种排序约束,否则使用它没有什么价值。此外,虽然实际内存可能不同,但在ccNUMA系统中,其他内存的视图始终是一致的
lock cmpxchgl %edx, (%ebx)
Example:
      mov   eax, OldDataA           //load Old first 32 bits
      mov   edx, OldDataB           //load Old second 32 bits
      mov   ebx, NewDataA           //load first 32 bits
      mov   ecx, NewDataB           //load second 32 bits
      mov   edi, Destination        //load destination pointer
      lock cmpxchg8b qword ptr [edi]
      setz  al                      //if transfer is succesful the al is 1 else 0