gcc,__ atomic -exchange似乎产生非原子asm,为什么?

时间:2015-09-05 23:10:14

标签: gcc assembly gas atomicity reentrancy

我正在开发一个很好的工具,它需要两个不同的64位值的原子交换。在amd64架构上,可以使用XCHGQ指令(参见doc中的警告:它是一个很长的pdf)。

相应地,gcc有一些原子内置函数,理想情况下也是如此,例如here可见。

使用这两个文档我生成了以下简单的C函数,用于两个64位值的原子交换:

void theExchange(u64* a, u64* b) {
  __atomic_exchange(a, b, b, __ATOMIC_SEQ_CST);
};

(顺便说一下,我并不清楚,为什么需要一个"原子交换" 3个操作数。)

对我来说有点可疑,gcc __atomic_exchange宏使用3个操作数,所以我测试了它的asm输出。我用gcc -O6 -masm=intel -S编译了这个,我得到了以下输出:

.LHOTB0:
        .p2align 4,,15
        .globl  theExchange
        .type   theExchange, @function
theExchange:
.LFB16:
        .cfi_startproc
        mov     rax, QWORD PTR [rsi]
        xchg    rax, QWORD PTR [rdi] /* WTF? */
        mov     QWORD PTR [rsi], rax
        ret
        .cfi_endproc
.LFE16:
        .size   theExchange, .-theExchange
        .section        .text.unlikely

正如我们所看到的,结果函数不仅包含单个数据移动,还包含三个不同的数据移动。因此,正如我所理解的那样,这个函数不是真正的原子。

怎么可能?也许我误解了一些文档?我承认,gcc内置文档对我来说并不是很清楚。

1 个答案:

答案 0 :(得分:2)

这是__atomic_exchange_n (type *ptr, type val, int memorder)的通用版本,其中只有ptr上的交换操作是原子的,val的读取不是。在通用版本中,val是通过指针访问的,但原子性仍然不适用于它。当编译器必须调用外部帮助程序时,指针是这样的,它将使用多种大小:

  

四个非算术函数(加载,存储,交换和   compare_exchange)也都有通用版本。这个通用   版本适用于任何数据类型。它使用无锁内置   如果特定数据类型大小使这成为可能;   否则,将在运行时解析外部呼叫。这个   外部调用与添加'size_t'的格式相同   插入的参数作为指示大小的第一个参数   被指向的对象。所有对象的大小必须相同。