環境
Linux : 3.15.10-200.fc20.x86_64
gcc 版本: 4.8.3 20140624 (Red Hat 4.8.3-1)
__sync_* 系列的函數 : 保證原子操作(lock 指令),也保證cpu寄存器數據一致性。(其實就是直接讀寫內存)
volatile : 保持寄存器數據一致性(每次重新讀寫內存到寄存器)
C代碼:
int main(void)
{
volatile int a = 10;
++a;
__sync_add_and_fetch(&a , 1);
a = 100;
a += 200;
a -= 100;
int b = 10;
++b;
b = 100;
b += 200;
b -= 100;
__sync_add_and_fetch(&a , b);
a += b;
return 0;
}
關鍵看這兩行代碼對應的彙編指令:
__sync_add_and_fetch(&a , b);
a += b;
彙編指令:
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $10, -8(%rbp)
movl -8(%rbp), %eax
addl $1, %eax
movl %eax, -8(%rbp)
lock addl $1, -8(%rbp)
movl $100, -8(%rbp)
movl -8(%rbp), %eax
addl $200, %eax
movl %eax, -8(%rbp)
movl -8(%rbp), %eax
subl $100, %eax
movl %eax, -8(%rbp)
movl $10, -4(%rbp)
addl $1, -4(%rbp)
movl $100, -4(%rbp)
addl $200, -4(%rbp)
subl $100, -4(%rbp)
movl -4(%rbp), %eax
lock addl %eax, -8(%rbp)
movl -8(%rbp), %edx
movl -4(%rbp), %eax
addl %edx, %eax
movl %eax, -8(%rbp)
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
1:在併發編程中,如果你有一個多個線程訪問的變量。如果你要保證它的有效性且不想加volatile修飾符的話,那麼就要做到每次修改或訪問都是使用gcc的原子操作。
2:
2.1 CAS(cpu 硬件同步原語(compare and swap)): http://baike.baidu.com/subview/18179/6777667.htm
2.2 volatile只是每次刷新值爲內存的值,沒有原子保證。
2.3 原子操作,其實就是保證這一步的過程是原子的。但是,沒有保證值不會變(ABA問題)。