0

以下のユーザーレベルのコード スニペットを作成して、atomicincxchg(Linux コードを参照) という 2 つのサブ関数をテストしました。私が必要としているのは、32 ビット整数に対して操作を実行することだけです。そのため、明示的に を使用していますint32_tglobal_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;
}

私の2つの質問は次のとおりです。

  1. これら 2 つのサブ関数は適切に記述されていますか?
  2. これを 32 ビットまたは 64 ビットのプラットフォームでコンパイルした場合、これは同じように動作しますか? たとえば、ポインター アドレスの長さが異なる可能性があります。または、オペランドと競合する可能性がinclありますか?xchgl
4

1 に答える 1

3

この質問に対する私の理解は以下のとおりです。間違っている場合は修正してください。

すべての read-modify-write 命令 (例: incl、add、xchg) にはロック プレフィックスが必要です。ロック命令は、メモリ バス上で 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

ところで、gcc の最適化を避けるために *ptr を volatile 変数にコピーする必要があると思います。

ウィリアム

于 2013-01-14T02:06:11.680 に答える