Skip to content

原子操作

Atomic operation

对并发观察者不可分割、可视为在单一瞬间完成的操作。

条目类型
定义

形式陈述

设共享对象由一台抽象状态机描述。称对象上的一个操作是原子的,若在抽象层面的并发对象历史中,它把对象从一个状态不可分割地转移到另一个状态:任何其他线程都观察不到它的中间状态。等价的表述是,每个原子操作可以被赋予一个位于其调用与返回之间的单一时刻(线性化点),仿佛整个效果在该瞬间一次性发生;操作之间的可见效果与按这些时刻排成的顺序执行一致。原子性是对"抽象历史中的粒度"的规定,与实现层的步数无关:一个操作可以由多条机器指令实现,只要并发观察者无法看穿其内部即可。

直觉

并发推理的根本困难在于交错:n 个线程各走若干步,可能的交错数量呈指数增长,逐一分析不可行。原子性是压缩这种复杂度的基本手段——把"许多小步"封装成"一大步"之后,观察者的世界里每个操作要么尚未发生、要么已全部发生,不存在完成一半的可见时刻,于是所有推理都可以在"操作序列"而非"指令交错"的粒度上进行。一个诚实的类比是照相机快门:无论内部机械多复杂,底片上只留下一个瞬间。但要注意这个类比的失效之处:原子性只承诺单个操作不可分割,丝毫不承诺多个原子操作的组合仍然不可分割——这正是大量并发 bug 的来源。

例子与边界

正例:原子读写寄存器保证读操作永远返回某次完整写入的值,不会出现"撕裂值"。反面对照能看清它防住了什么:在只支持 32 位原子访问的机器上用两条指令写一个 64 位数,并发读者可能读到"前一半旧值、后一半新值"拼成的从未被写入过的数——原子性排除的正是这种中间状态泄露。

边界情形之一是复合操作:先原子地读 x、再在 x 满足条件时原子地写,这两步各自原子,但整体不原子——另一线程可在两步之间修改 x,造成 check-then-act 竞态。消除它需要把"读—判—写"合并为单个原子的读改写操作,例如比较并交换。之二是术语歧义:数据库事务的"原子性"指故障时全做或全不做(失败原子性),与这里的并发不可分割性相关但不相同。之三是排序:硬件原子指令的语义还涉及内存排序、访问宽度与对齐,原子性本身不提供跨位置的顺序保证,弱内存模型下仍需 acquire/release 等排序约束才能建立线程间的可见性推理。

原子 fetch_add 可避免两个线程同时递增时丢失更新;普通“读计数、加一、写回”由三步组成,可能发生竞态。两个原子变量分别更新并不能保证读者只看到“两者都旧或都新”。在弱内存模型下,原子操作还需选择 acquire/release 等顺序语义。

推论与应用

原子操作是同步对象的实现基础:互斥锁可用原子测试与更新转移所有权,信号量实现则需原子维护许可计数及等待队列状态,引用计数依赖原子增减,无锁数据结构以比较并交换为骨架并追求lock-free 进展。这些对象各自还规定所有权、阻塞或唤醒语义,不能从“底层更新是原子的”直接推出完整接口正确性。

在正确性理论中,为每个操作指定线性化点是证明线性一致性的标准手法,原子操作因此连接实现与顺序规格。不同原子原语的表达力并不相同;它们能为多少参与者实现何种对象,由共识数层级统一刻画。

参考资料
  • Maurice Herlihy and Nir Shavit, The Art of Multiprocessor Programming, rev. 1st ed., Morgan Kaufmann, 2012,Chs. 1–18。
  • Hagit Attiya and Jennifer Welch, Distributed Computing: Fundamentals, Simulations, and Advanced Topics, 2nd ed., Wiley, 2004,Chs. 1–18。
关系图谱18 个相邻概念 · 2 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组
类型化关系

被这些条目使用