原子比较C中两个整数的最快方法?

时间:2011-06-26 06:22:11

标签: c caching atomic bit

uint64_t n;      // two 32-bit integers

return ( (uint32_t)(n >> 32) == (uint32_t)n );

将32个最高有效位与uint64_t的32个最低有效位进行原子比较的最快方法是什么?

我认为一个可怕的解决方案是:获取自旋锁,读取32 LSB,读取32 MSB,比较得到结果,释放自旋锁,返回结果。有没有办法在不必使用自旋锁的情况下做到这一点?

5 个答案:

答案 0 :(得分:9)

如何在两个不同的地址上使用比较交换操作?

类似于:CMPXCHG (int*)&n, (((int*)&n)+1)(注意 - 这实际上不起作用)。

编辑:将语法更改为更接近实际的x86语法。

如Serge所指出的那样

编辑2:,大​​多数程序集都不支持在汇编指令中使用两个内存地址,因此这种方式无法直接从内存中运行。这意味着该方法不能用于以原子方式比较64位变量的两个32位部分。

某些程序集(至少是PowerPC)能够提供特殊指令(对于PowerPC,LWARX和STWCX),可以使其以多线程安全的方式工作,但它不是OP所要求的,也不是为x86工作。

答案 1 :(得分:7)

这整个操作(内存中两个值的原子比较)是没有意义的,除非你还能确保写它们总是原子的。它也受到固有的竞争条件的影响;当你确定他们是平等的时候他们可能已经改变了,反之亦然。无论你想要解决的问题几乎肯定都需要锁定,而不是原子操作。

答案 2 :(得分:3)

  1. 只有在平台上能够以原子方式检索64位数时,才能无锁地执行此操作。如果有可能那么首先 - 你以自己喜欢的方式原子地检索64位值(例如64位窗口上的InterlockedOr64(ptr,0),如果你有32位x86 CPU就没有办法 - 除非你英特尔CPU不比奔腾更老,你确保你的64位值是64位对齐,不确定其他供应商的x86 CPU),第二 - 与你检索的值进行比较。

  2. 你显然不能以便携方式做到这一点。在无法自动获取64位数字的平台上,没有锁定就无法做到这一点。

  3. 修改

    由于一些严重误导性的想法在本次讨论中受到了极大的欢迎,我觉得我有责任写一些关于未能使用比较和交换32位数字来解决问题的笔记。

    假设我们有x86平台,那么我们可以编写asm代码:

        mov eax, [num+4]
        lock cmpxchg [num], eax
        jz  equal_case_code
        ; non-equal case code follows
    equal_case_code:
        ; equal case code follows
    

    显然这个实现不是原子的 - 在movcmpxchg指令之间可能会中断线程(因为在一条指令中不允许有两个内存操作数)。

    来自不同API的32位比较和交换功能(如来自Win32 API的InterlockedCompareExchange)无法提供正确的解决方案,因为它们的语义只允许原子访问一个32位内存地址。

答案 3 :(得分:0)

使用联盟怎么样?像这样:

typedef union {
    uint32_t small[2];
    uint64_t full;
} bigint_t;

然后你去做:

uint64_t n;      // two 32-bit integers

bigint_t mybigint;
mybigint.full = n;
return mybigint.small[0] == mybigint.small[1];

我不知道这是否是最快的,但是如果你没有将uint64_t复制到union中但直接使用union,它应该非常快,因为它不需要做任何比较。

答案 4 :(得分:0)

使用内联汇编将64位整数加载到MMX或SSE寄存器(64位读取是原子的),然后比较这两半。