为什么__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变量,我想原子地增加,因为该变量是多线程程序中的计数器. 如果我为一个amd64系统(-m64)编译,那么生成的汇编代码很容易理解. 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> 这是我不明白的: > 可能没有关系,如果有一个“脏的阅读”,但有人可以提出一个简短的证明,没有问题? 进一步:为什么生成的代码跳回到0x8048565而不是0x804855a?我很肯定,只有其他作家也只是增加变量,这只是正确的.这是对__sync_add_and_fetch函数的牵连需求吗? 解决方法
读取由于正确对齐而被保证是原子的(并且它适合于一条缓存行),而且由于英特尔以这种方式制定了规范,请参阅英特尔架构手册第1卷4.4.1:
第3A卷8.1.1:
因此,通过对齐,它可以在1个循环中读取,并且它适合于使读取原子的一个高速缓存行. 由于指针已经被加载,所以代码跳转到0x8048565,因为CMPXCHG8B将无法加载它们,因为CMPXCHG8B会将EAX:EDX设置为目标值,如果失败: CMPXCHG8B Intel ISA手册的说明书Vol. 2A:
因此,代码只需要增加新返回的值,然后重试. value = dest; While(!CAS8B(&dest,value,value + 1)) { value = dest; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |