0

我编写了以下用户级代码片段来测试两个子函数,原子incxchg(参考 Linux 代码)。我需要的只是尝试对 32 位整数执行操作,这就是我明确使用int32_t. 我假设global_counter将由不同的线程进行比赛,虽然tmp_counter很好。

#include <stdio.h>
#include <stdint.h>
int32_t global_counter = 10;

/* Increment the value pointed by ptr */
void atomic_inc(int32_t *ptr)
{
    __asm__("incl %0;\n"
        : "+m"(*ptr));
}

/* 
 * Atomically exchange the val with *ptr.
 * Return the value previously stored in *ptr before the exchange
 */
int32_t atomic_xchg(uint32_t *ptr, uint32_t val)
{
    uint32_t tmp = val;
    __asm__(
        "xchgl %0, %1;\n"
        : "=r"(tmp), "+m"(*ptr)
        : "0"(tmp)
        :"memory");
    return tmp;
}

int main()
{
    int32_t tmp_counter = 0;

    printf("Init global=%d, tmp=%d\n", global_counter, tmp_counter);

    atomic_inc(&tmp_counter);
    atomic_inc(&global_counter);
    printf("After inc, global=%d, tmp=%d\n", global_counter, tmp_counter);

    tmp_counter = atomic_xchg(&global_counter, tmp_counter);
    printf("After xchg, global=%d, tmp=%d\n", global_counter, tmp_counter);

    return 0;
}

我的两个问题是:

  1. 这两个子函数写得正确吗?
  2. 当我在 32 位或 64 位平台上编译它时,它的行为是否相同?例如,指针地址是否可以具有不同的长度。或者可能incl并且xchgl将与操作数冲突?
4

1 回答 1

3

我对这个问题的理解如下,如果我错了,请纠正我。

所有读-修改-写指令(例如:incl、add、xchg)都需要一个锁定前缀。lock指令是通过在内存总线上断言LOCK#信号来锁定其他CPU访问的内存。

Linux 内核中的 __xchg 函数暗示没有“锁定”前缀,因为无论如何 xchg 总是暗示锁定。http://lxr.linux.no/linux+v2.6.38/arch/x86/include/asm/cmpxchg_64.h#L15

但是, atomic_inc 中使用的 incl 没有这个假设,因此需要 lock_prefix。 http://lxr.linux.no/linux+v2.6.38/arch/x86/include/asm/atomic.h#L105

顺便说一句,我认为您需要将 *ptr 复制到 volatile 变量以避免 gcc 优化。

威廉

于 2013-01-14T02:06:11.680 回答