10

您将如何使用嵌入式机器代码(假设,假设 x86 架构)在 C 中编写一个对整数值进行原子比较和交换的函数?如果它只为 i7 处理器编写,它可以更具体吗?

翻译是否充当记忆栅栏,或者它只是确保在比较和交换中包含的那个记忆位置上的排序关系?与内存围栏相比,它的成本是多少?

谢谢你。

4

5 回答 5

7

最简单的方法可能是使用像_InterlockedCompareExchange()这样的编译器内在函数。它看起来像一个函数,但实际上是编译器中的一种特殊情况,可以归结为单个机器操作。在 MSVC x86 内在的情况下,它也可以用作读/写栅栏,但在其他平台上不一定如此。(例如,在 PowerPC 上,您需要显式发出lwsync来隔离内存重新排序。)

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

于 2010-11-18T10:24:48.613 回答
7

您可以使用CMPXCHG带有前缀的指令LOCK进行原子执行。

例如

lock cmpxchg DWORD PTR [ebx], edx

或者

lock cmpxchgl %edx, (%ebx)

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

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

于 2010-11-18T11:14:46.637 回答
4

如果您的整数值是 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
于 2010-11-18T11:48:45.560 回答
4

如果在原子处理器指令中省略 LOCK 前缀,则无法保证跨多处理器环境的原子操作。

在多处理器环境中,LOCK# 信号确保处理器在信号被断言时独占使用任何共享内存。英特尔指令集参考

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

于 2011-02-15T13:33:31.333 回答
2

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

A "Load Linked" instruction tells the processor to read a memory location and watch in some way to see if it might be written. A "Conditional Store" instruction instructs the processor to write a memory location only if nothing can have written it since the last "Load Linked" operation. Note that the determination may be pessimistic; processing an interrupt, for example, may invalidate a "Load-Linked"/"Conditional Store" sequence. Likewise in a multi-processor system, an LL/CS sequence may be invalidated by another CPU accessing to a location on the same cache line as the location being watched, even if the actual location being watched wasn't touched. In typical usage, LL/CS are used very close together, with a retry loop, so that erroneous invalidations may slow things down a little but won't cause much trouble.

于 2012-05-10T18:31:19.353 回答