Back to Blog

面试题【1】:i++是否原子操作?并解释为什么?

上述汇编代码直接对应了前述的三阶段实现:先读取、再自增、最后写回。显而易见,这不是原子操作,如果不加锁互斥,在多线程环境下会产生错误

优化模式下的可能变化

即使打开了编译器优化,编译器也不一定会把 i++ 编译成单条 inc dword ptr[i]。是否使用单指令取决于:

  • 表达式的使用场景:如果 i++ 的结果需要在后续计算中使用(例如 int j = i++;),编译器必须保留原始值,因而仍会展开为读取‑自增‑写回的三步。
  • 编译器的内部策略:不同编译器、不同版本甚至同一编译器的不同设置,都会影响最终生成的指令序列。

单指令 inc dword ptr[i] 的局限

即便编译器在某些情况下生成了 inc dword ptr[i](单条自增指令),这在 单核 CPU 上看似安全,因为同一时刻只有一个执行流能够访问总线。但在 多核 CPU 环境中,两个核心可以几乎同时执行 inc,导致以下情况:

  • 核心 A 读取旧值 5,准备写回 6。
  • 核心 B 同时读取旧值 5,准备写回 6。
  • 两个写回操作先后完成,最终内存只增加了 一次(仍是 6),而不是预期的两次(7)。

因此,即使出现了单指令自增,也不能保证在多核系统上是原子操作

真正的原子自增指令:lock inc

在 x86 架构中,lock 前缀的指令能够在总线层面锁住对应的内存地址,确保同一时刻只有一个 CPU 能对该地址进行读‑改‑写操作。对应的原子自增指令形式为: