Non-atomic_vs_atomic

(未完成)有 nonatomic 和 atomic 引申开去

iOS 有一道很基础的面试就是“nonatomic 和 atomic 有什么区别?”,如果回答:一个非原子操作,另一个是原子操作。那么会进一步问:“atomic 的原子操作是线程安全的吗?”,相信大多数人都知道答案——不是,但是随着这道面试题被引用的次数越来越多,传播的越来越广,答案逐渐被简化成了“不安全”,这就偏离了出题人的考察初衷。
因为这个问题也困扰了自己很久,今天终于小有领会,所以特此总结。

什么是原子操作

要弄清楚这个问题,首先明白什么是原子操作,原子操作是指“不可中断的一个或者一系列操作,也就是不会因线程调度而打断,运行期间不会有任何上下文的切换(context switch)。

什么是线程安全 这个是自己的理解,但是也需要进一步验证。

所谓线程安全就是:当有多个线程访问同一块内存,不会出现数据错乱,结果应始终是可预料的,或者在可预料的范围内。例如:假设有内存,其存储的是字符串 “hello”,A、B 两个线程同时访问,A 要读取,B 要把 “hello” 更新为字符串 “hi”。如果无论 A、B 操作的顺序如何,只要 A 在读取完之前,B 不可写入,或者 B 写入之前,A 不可读,那么这就是线程安全的;相反,如果不是线程安全的,B 只写了一半,就被 A 读取了,那么此时 A 读取的值就是不可预料的,因为它可能既不是 “hello”,也不是 “hi”。
试想一下,线程安全其实解决的是记过是否正确的问题,只有解决这个问题,才进一步考虑结果是否是我们想要的结果。

单核处理器和多核处理器的区别

早期的 CPU 只有一个核心,同一时间内只有一个线程在运行,CPU 必须在各个线程间切换,以实现多任务。此时一条指令中完成的操作即可看作是原子操作,因为中断只发生在指令间。而到了多核 CPU 时代,CPU 可以同时运行 2 个甚至以上的核心,也就是说可以同时运行多个线程,实现了真正的并行,此时再执行类似 i++
--i
这样的操作就可能因为多个线程同时操作同一块内存从而出现无法预料的结果。
软件级别的原子操作是依赖于硬件支持的. 在 x86 体系中, CPU 提供了 HLOCK pin 引线, 允许 CPU 在执行某一个指令(仅仅是一个指令)时拉低 HLOCK pin 引线的电位, 直到这个指令执行完毕才放开. 从而锁住了总线, 如此在同一总线的CPU就暂时无法通过总线访问内存了, 这样就保证了多核处理器的原子性. (想想这机制对性能影响挺大的)

atomic 属性

atomic 修饰符用来向编译器表明:在生成指令时要保证同一时间内只有一个线程在访问。虽然数据不会发生错乱了,但是因为顺序没有保证,所以最终的结果仍然可能不是我们想要的。
???这里感觉不对,还有待进一步考证。

参考

单核,多核 CPU 的原子操作

关于 atomic 为何不安全

Intel support forums

Atomic vs. Non Atomic Properties Crash Course