探究iOS多线程究竟不安全在哪里?

2020-01-18 20:42:47王冬梅

当然我们也会遇到少数场景需要追求代码的性能,比如编写framework,或者在多线程读写共享数据频繁的场景,我们需要大致了解锁带来的损耗到底有多少。

官方文档有个数据,使用Intel-based iMac with a 2 GHz Core Duo processor and 1 GB of RAM running OS X v10.5测试,获取mutex有大概0.2ms的损耗,我们可以认为锁带来的损耗大致在ms级别。

Atomic Operations

其实除了各种锁之外,iOS上还有另一种办法来获取原子性,使用Atomic Operations,相比锁的损耗要小一个数量级左右,在一些追求高性能的第三方Framework代码里可以看到这些Atomic Operations的使用。这些atomic operation可以在/usr/include/libkern/OSAtomic.h中查到:

ios,多线程安全,多线程,多线程开发

比如


_intA ++;

是非原子性的。


OSAtomicIncrement32(&(_intA));

是原子性的,多线程安全的。

Atomic Operation只能应用于32位或者64位的数据类型,在多线程使用NSString或者NSArray这类对象的场景,还是得使用锁。

大部分的Atomic Operation都有OSAtomicXXX,OSAtomicXXXBarrier两个版本,Barrier就是前面提到的memory barrier,在多线程多个变量之间存在依赖的时候使用Barrier的版本,能够保证正确的依赖顺序。

对于平时编写应用层多线程安全代码,我还是建议大家多使用@synchronized,NSLock,或者dispatch_semaphore_t,多线程安全比多线程性能更重要,应该在前者得到充分保证,犹有余力的时候再去追求后者。

尽量避免多线程的设计

无论我们写过多少代码,都必须要承认多线程安全是个复杂的问题,作为程序员我们应该尽可能的避免多线程的设计,而不是去追求高明的使用锁的技能。

后面我会写一篇文章,介绍函数式编程及其核心思想,即使我们使用非函数式的编程语言,比如Objective C,也能极大的帮助我们避免多线程安全的问题。

总结

iOS下多线程不安全的分析至此结束了,如何编写多线程安全的代码,说到底还是在于对memory layout和原子性的理解,也希望这篇文章将atomic和nonatomic的真正区别解释清楚了:)。如果有疑问大家可以留言交流。


注:相关教程知识阅读请移步到IOS开发频道。