看了YY系列作者的不再安全的 OSSpinLock,有心整理一下iOS上会用到的锁,包括OSSpinLock、pthread_mutex、NSCondition、NSRecursiveLock、NSConditionLock,以及能实现锁功能的dispatch_semaphore和@synchronized, OSSpinLock和pthread_mutex的可见性为内核态,其他为用户态。
谈及各种同步机制的PK,个人觉得这篇文章整理得比较不错,推荐给大家。(备注:不过纠正一点,这篇文章说MacOS/iOS没有提供读写锁,实际上pthread库里是有提供读写锁的)
以下会简单整理每种同步方案的特性和使用方法,使用方法都以Objctive-C中不安全NSMutableDictionary的读写为例,先创建NSMutableDictionary:
OSSpinLock
特性:
OS X/iOS自有的自旋锁,线程等待取锁不挂起,直接保持空转,做忙等待,适用锁区比较短的场景,不支持递归。
但OSSpinLock现在已经不再安全,在不同优先级的多线程调度中,会有优先级反转问题,破坏spin lock。
使用:
|
|
pthread_mutex
特性:
多线程库(pthread)基于互斥体的同步锁,是最常用的锁对象,并且支持递归,性能和稳定性都是公认最好的,比较推荐使用。pthread_mutex也有不好的地方,一次只能一个线程持有锁,且阻塞等待对象(阻塞等待对象也是他比自旋锁慢的原因)。
使用:
|
|
dispatch_semaphore
特性:
GCD中用于控制多线程并发的信号量,可以通过wait/signal的信号事件控制多线程最大并发数,当最大并发数控制在1的时候,就可以当做同步锁使用,但这种方式不支持递归。
使用:
|
|
NSLock/NSRecursiveLock
特性:
都是Apple官方实现提供的面向对象的同步锁,都遵循Objective-C的NSLocking协议,NSLock支持tryLock,NSRecursiveLock支持递归(递归锁).
使用:
|
|
NSCondition/NSConditionLock
特性:
基于信号量方式实现的锁对象,用来解决类似生产者消费者问题,前者提供单独的信号量管理接口,相比后者用法上可以更为灵活,而后者在接口上更为直接、实用;
使用:
NSCondition/NSConditionLock是用来解决类似生产者消费者问题,并不适用保护不安全NSMutableDictionary的读写,下面简单贴出NSCondition实现的生产者消费者问题代码:
|
|
@synchronized(){}
特性:
Objective-C实现的同步语法,可以给任何Objective-C对象加锁,block里执行锁区代码。@synchronizd(){}在多线程同步方案中效率是最低,原因是他的block会隐式添加异常处理来保护代码块,但@synchronizd(){}在代码书写方面比较简便。
使用:
|
|
property 之 atomic
Objective-C中属性的可选操作atomic,利用get/set接口的属性实现原子操作,以确保对象的属性变量在多线程中读写安全,这也实现了同步读写操作。