增量算子的原子性

时间:2015-01-16 04:08:16

标签: c atomic language-lawyer atomicity

在接受采访时我被告知,在C语言中,使用++运算符(比如说i ++)是一个原子操作,比如说" i + = 1"不是。我认为这些操作在线程安全性或原子性方面完全相同。我错过了什么或者这些实际上是不同的吗?

3 个答案:

答案 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)操作进行原子增量。