在接受采访时我被告知,在C语言中,使用++运算符(比如说i ++)是一个原子操作,比如说" i + = 1"不是。我认为这些操作在线程安全性或原子性方面完全相同。我错过了什么或者这些实际上是不同的吗?
答案 0 :(得分:10)
这是无稽之谈。根据数据类型,体系结构以及编译器(标准不保证一般的原子性,除非你使用的是C11原子),其中一个可能是也可能不是原子的,但我看不到任何有充分的理由认为,i++
通常是i += 1
不是{{1}}的原子。在不使用表达式结果的上下文中,它们很可能实际生成相同的代码。
答案 1 :(得分:8)
语句* i++;
和i += 1;
在C中是等效的。两者都不保证是原子的。
特别是,大于系统字大小的变量的增量(例如,32位系统上的64位变量)几乎总是非原子的,因为以原子方式递增这样的变量通常需要显式锁定。此外,某些体系结构不支持直接在内存中递增变量。 (也就是说,它们需要显式的加载/修改/存储序列。)这些体系结构不能在没有锁定的情况下以原子方式修改任何变量。
*被视为独立语句,而不是表达式
答案 2 :(得分:2)
我使用gcc-4.8.2 -O2
-S
void increment1(int *a) {
*a += 1;
}
void increment2(int *a) {
(*a)++;
}
两者都准确生成the same
汇编
increment1:
.LFB0:
.cfi_startproc
addl $1, (%rdi)
ret
.cfi_endproc
.LFE0:
.size increment1, .-increment1
.p2align 4,,15
.globl increment2
.type increment2, @function
increment2:
.LFB1:
.cfi_startproc
addl $1, (%rdi)
ret
.cfi_endproc
但是在更精确的技术目标的背景下,它们都是atomic write
,这意味着它不提供 MAD 结果。
如果在32位或更少位的CPU环境中使用int64_t变量,则64位修改会导致多次写入操作。如果没有锁定,则不能atomic write
。
您可以在gcc环境中使用__sync_fetch_and_add(&a, 1)
操作进行原子增量。