は、次の凝縮のコードを考えてみましょう:__sync_add_and_fetchが32ビットシステム上の64ビット変数に対して動作するのはなぜですか?
/* Compile: gcc -pthread -m32 -ansi x.c */
#include <stdio.h>
#include <inttypes.h>
#include <pthread.h>
static volatile uint64_t v = 0;
void *func (void *x) {
__sync_add_and_fetch (&v, 1);
return x;
}
int main (void) {
pthread_t t;
pthread_create (&t, NULL, func, NULL);
pthread_join (t, NULL);
printf ("v = %"PRIu64"\n", v);
return 0;
}
変数は、マルチスレッドのプログラムカウンタであるので、私は、私はアトミックにインクリメントしたいuint64_t
変数を持っています。 原子性を達成するために、私はGCCのatomic builtinsを使用します。
amd64システム(-m64)用にコンパイルすると、生成されたアセンブラコードがわかりやすくなります。 lock addq
を使用すると、プロセッサはインクリメントをアトミックにすることを保証します。
400660: f0 48 83 05 d7 09 20 lock addq $0x1,0x2009d7(%rip)
しかし、同じCコードは、IA32システム(-m32)上の非常に複雑なASMコードを生成します。ここでは
804855a: a1 28 a0 04 08 mov 0x804a028,%eax
804855f: 8b 15 2c a0 04 08 mov 0x804a02c,%edx
8048565: 89 c1 mov %eax,%ecx
8048567: 89 d3 mov %edx,%ebx
8048569: 83 c1 01 add $0x1,%ecx
804856c: 83 d3 00 adc $0x0,%ebx
804856f: 89 ce mov %ecx,%esi
8048571: 89 d9 mov %ebx,%ecx
8048573: 89 f3 mov %esi,%ebx
8048575: f0 0f c7 0d 28 a0 04 lock cmpxchg8b 0x804a028
804857c: 08
804857d: 75 e6 jne 8048565 <func+0x15>
は、私は理解していないものです:
lock cmpxchg8b
は、変更された変数が期待値が依然としてターゲットアドレスにある場合にのみ書き込まれることを保証します。 compare-and-swapは、アトミックに行われることが保証されています。- しかし、 0x804855aと0x804855fの変数の読み取りがアトミックであることを保証するものは何ですか?
おそらく「ダーティリードが」あった場合、それは問題ではありませんが、誰かが問題がないことを短い証拠を概説してくださいだろうか?
さらに、生成されたコードが0x8048565ではなく0x80485565に戻るのはなぜですか?私はこれが正しかったのは、他の作家も変数をインクリメントするだけであるということです。これは、__sync_add_and_fetch
機能のための関係する要件ですか?