我在多线程程序中使用了一些全局结构,一些成员被多个线程同时修改,而另一些则不是。
我没有定义任何 volatile 成员,但无论何时我将此成员用于读写目的,我都会使用原子内置函数,例如 __sync_fetch_and_add。
问题是,我应该定义这个成员还是整个 struct volatile?
我认为编译器必须访问内存而不是任何寄存器,因为这个内置函数(锁定前缀),我是否应该担心其他不会导致竞争条件的成员。
我检查了我的编译器(gcc 4.6.2)的汇编输出,看来我的假设是正确的。
这是测试代码。
int sum = 0;
for (i=0; i<2000000000; i++) {
sum += i;
}
汇编输出(-O2 -S -masm=intel)
L2:
add edx, eax
inc eax
cmp eax, 2000000000
jne L2
所以编译器永远不会访问内存(eax = i,edx = sum)
这是第二个测试代码。
volatile int sum = 0;
for (i=0; i<2000000000; i++) {
sum += i;
}
汇编输出
L2:
mov edx, DWORD PTR [esp+28]
add edx, eax
mov DWORD PTR [esp+28], edx
inc eax
cmp eax, 2000000000
jne L2
编译器每次都按预期访问内存求和。
最终代码,我的方式。
int sum = 0;
for (i=0; i<2000000000; i++) {
__sync_fetch_and_add(&sum , i);
}
程序集输出。
L2:
lock add DWORD PTR [esp+28], eax
inc eax
cmp eax, 2000000000
jne L2
甚至没有像以前(edx)那样的临时寄存器,编译器每次都访问内存。
因此,我不定义 volatile 任何由多个线程修改或一次仅由一个线程修改的成员。我安全吗?
提前致谢。