C++ 中的赋值操作和自增操作的原子性

Mar 6, 2016


做题时碰到个有争议的题目。

题意大概是这样的。 两个线程并行运行下面的代码,问可能的结果。

void fun() {
    ++x;
    printf("%d", x);
}

这题的关键是++x在 C++ 中并不像在 Java 中一样不是原子操作。所以这题就变成了考虑 printf 的并行性。

我们来看一下 ++x 的汇编代码。

int main() {
    int a = 0;
    ++a;
    return 0;
}
_main:
LFB9:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	andl	$-16, %esp
	subl	$16, %esp
	call	___main
	movl	$0, 12(%esp)
	addl	$1, 12(%esp)
	movl	$0, %eax
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc

显然,编译器只用一条语句就完成了自增操作。

而赋值语句

int main() {
    c = a;
    return 0;
}
_main:
LFB8:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	andl	$-16, %esp
	subl	$16, %esp
	call	___main
	movl	$100, 12(%esp)
	movl	$0, 8(%esp)
	movl	12(%esp), %eax
	movl	%eax, 8(%esp)
	movl	$0, %eax
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc

一共用了三步,所以不是原子的。