- 说下OperationQueue 和 GCD 的区别,和各自的优势
- 线程安全的处理手段有哪些
- OC你了解的锁有哪些,在你回答的基础上进行二次提问
iOS 中的线程同步方案
OSSpingLock
os_unfair_lock
pthread_mutex
dispatch_semaphore
dispatch_queue(DISPATCH_QUEUE_SERIAL)
NSLock
NSRecursiveLock
NSCondition
NSConditionLock
@synchronized
OSSpingLock
OSSpingLock 叫做“自旋锁”,等待锁的线程会处于忙等状态(busy-wait),一直占着CPU资源。
目前已经不再安全,可能会出现优先级翻转问题
如果等待锁的线程的优先级高,他会一直占着CPU资源,优先级低线程就无法释放锁
需要导入头文件 #import <libkern/OSAtomic.h>
//初始化
OSSpinLock lock = OS_SPINLOCK_INIT;
// 尝试加锁(如果需要等待就不加锁,直接返回false,如果不需要等待就加锁返回true)
bool result = OSSpinLockTry(&lock);
// 加锁
OSSpinLockLock(&lock)
// 解锁
OSSpinLockUnlock(&lock)
os_unfair_lock
os_unfair_lock用于取代不安全的OSSpinLock,从iOS10开始才支持
从底层调用看,等待os_unfair_lock锁的线程会处于休眠状态,并非忙等
需要导入头文件 #import <os/lock.h>
// 初始化
os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
// 尝试加锁
os_unfair_lock_trylock(&lock);
// 加锁
os_unfair_lock_lock(&lock);
// 解锁
os_unfair_lock_unlock(&lock);
pthread_mutex
mutex叫做“互斥锁”,等待加锁的线层会处于休眠状态
徐亚导入头文件 #import <pthread.h>
// 初始化锁的属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_NORMAL);
// 初始化锁
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,&attr);
//尝试加锁
pthread_mutex_trylock(&mutex);
// 加锁
pthread_mutex_lock(&mutex);
// 解锁
pthread_mutex_unlock(&mutex);
// 销毁相关资源
pthread_mutexattr_destroy(&attr);
pthread_mutex_destroy(&mutex);
/*
* Mutex type attributes
*/
#define PTHREAD_MUTEX_NORMAL 0
#define PTHREAD_MUTEX_ERRORCHECX 1
#define PTHREAD_MUTEX_RECURSIVE 2
#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
pthread_mutex - 递归锁
// 初始化锁的属性
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
// 初始化锁
pthread_mutex_t mutex;
pthread_mutex_init(&mutex,&attr);
自旋锁、互斥锁的比较
什么情况下使用自旋锁比较划算
预计线程等待锁的时间很短
加锁的代码(临界区)经常被调用,但竞争情况很少发生
CPU资源不紧张
多核处理器
什么情况下使用互斥锁比较划算
预计线程等待时间较长
单核处理器
临界区有IO操作
临界区代码复杂或者循环量大
临界区竞争非常激烈
atomic
atomic用于保证属性setter、getter的原子性能操作,相当于在getter和setter内部加了线程同步的锁
可以参考源码objc4的objc-accessors.mm
它并不能保证使用属性的过程中是线程安全的。
iOS中的读写安全方案
思考如何实现如下场景
同一时间,只能有一个线程进行写的操作
同一时间,允许多个线程进行读写操作
同一时间,不允许既有写的操作,还有读的操作
上面的场景就是典型的“多读单写”,经常用于文件等数据的读写操作,iOS中的实现方案有
pthread_rwlock: 读写锁
dispatch_barrier_async:异步栅栏调用