3.0 KiB
3.0 KiB
你的理解已经非常接近核心了,但如果从底层并发编程的角度来看,“不可中断”和“最小”这两个词需要更精确的定义。
在计算机科学中,**原子操作(Atomic Operation)**的重点确实有两个,但通常表述为:不可分割性(Indivisibility) 和 可见性(Visibility)。
1. 重点一:不可分割性(Indivisibility)—— 你说的“最小”
“原子”一词源于希腊语 atomos,意为“不可切分”。
- 含义:一个操作要么全部执行成功,要么完全不执行。在执行过程中,绝不会停在中间某个状态。
- 为什么不是单纯的“最小”?:有些原子操作在底层可能包含多个微指令(例如 CAS 操作),但 CPU 保证这些指令在逻辑上是一个整体。
- 现象:对于其他线程来说,它们永远观察不到这个操作的“中间结果”。
2. 重点二:排他性/原子性(Atomicity)—— 你说的“不可中断”
这里需要区分**“软件中断”和“硬件并发访问”**。
- 非原子操作的危机:比如
i++。它在 CPU 层面分为三步:- 从内存读
i到寄存器。 - 寄存器加 1。
- 写回内存。 如果你在第 2 步执行完,还没来得及写回内存时,线程被中断(上下文切换)了,另一个线程进来读到了旧的值,就会导致数据错乱。
- 从内存读
- 原子操作的保证:原子操作通过硬件锁(如总线锁或缓存锁)保证,在操作完成之前,没有任何其他核心或线程能干预这块内存。
3. 一个常被忽略的重点:内存顺序(Memory Ordering)
除了你提到的两点,现代高级编程(尤其是你熟悉的 C++20 或 Rust)中,原子操作还有一个至关重要的属性:同步与可见性。
- 可见性:当线程 A 完成一个原子写操作,线程 B 必须能立即“看到”这个修改。
- 防止重排序:编译器和 CPU 为了优化性能,经常会乱序执行指令。原子操作(配合内存序
std::memory_order)能像一道屏障一样,告诉 CPU:“不要把我前后的指令乱跳”,确保逻辑顺序正确。
总结:你的理解对吗?
- “最小”:对。它是逻辑上的最小单位,不可再分。
- “不可中断”:对。它保证了操作的连贯性,不会被线程切换或竞争对手打断。
底层小知识: 在 x86 架构下,普通的对齐内存地址的
mov(赋值)指令本身就是原子的。但像add这种复合操作,必须加上LOCK前缀指令,才能变成真正的“原子操作”。
既然你之前研究过 E2hangJson 的开发,在处理多线程解析或者全局引用计数时,你应该接触过 std::atomic。
想看看在 C++ 中,一个简单的 i++ 是如何通过汇编指令变成加锁的原子操作的吗?我们可以对比一下 LOCK 前缀的效果。