一:十种线程锁
我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这时候就需要我们保证每次只有一个线程访问这一块资源,锁 应运而生。
这里顺便提一下,上锁的两种方式trylock和lock使用场景:
当前线程锁失败,也可以继续其它任务,用 trylock 合适
当前线程只有锁成功后,才会做一些有意义的工作,那就 lock,没必要轮询 trylock
以下是十种线程锁所用时间:
1、OSSpinLock (自旋锁)
测试中效率最高的锁, 不过经YYKit作者确认, OSSpinLock已经不再线程安全,OSSpinLock有潜在的优先级反转问题
需要导入头文件 #import <libkern/OSAtomic.h> // 初始化 OSSpinLock spinLock = OS_SPINLOCK_INIT; // 加锁 OSSpinLockLock(&spinLock); // 解锁 OSSpinLockUnlock(&spinLock); // 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO OSSpinLockTry(&spinLock) /* 注:苹果爸爸已经在iOS10.0以后废弃了这种锁机制,使用os_unfair_lock 替换, 顾名思义能够保证不同优先级的线程申请锁的时候不会发生优先级反转问题. */
2、os_unfair_lock(互斥锁)
需要导入头文件 #import <os/lock.h> // 初始化 os_unfair_lock unfair_lock = OS_UNFAIR_LOCK_INIT; // 加锁 os_unfair_lock_lock(&unfair_lock); // 解锁 os_unfair_lock_unlock(&unfair_lock); // 尝试加锁,可以加锁则立即加锁并返回 YES,反之返回 NO os_unfair_lock_trylock(&unfair_lock); /* 注:解决不同优先级的线程申请锁的时候不会发生优先级反转问题. 不过相对于 OSSpinLock , os_unfair_lock性能方面减弱了许多. */
3、dispatch_semaphore (信号量)
// 初始化 dispatch_semaphore_t semaphore_t = dispatch_semaphore_create(1); // 加锁 dispatch_semaphore_wait(semaphore_t,DISPATCH_TIME_FOREVER); // 解锁 dispatch_semaphore_signal(semaphore_t); /* 注: dispatch_semaphore 其他两个功能 1.还可以起到阻塞线程的作用. 2.可以实现定时器功能,这里不做过多介绍. */
二:锁的类型
1、自旋锁
OSSpinLock 就是典型的自旋锁
自旋锁的特点是在没有获取到锁时既锁已经被添加,还没有被解开时. OSSpinLock处于忙等状态,一直占用CPU资源,类似如下伪代码:
while(锁没解开);
关于优先级反转问题
由于线程调度,每条线程的分配时间权重不一样,当权重小的线程先进入OSSpinLock优先加锁,当权重大的线程再来访问,就阻塞在这,可能权重大的线程会一直分配到cpu所以一直会进来,但是因为有锁,只能等待,权重小的线程得不到cpu资源分配,所以不会解锁,造成一定程度的死锁.
2、互斥锁
os_unfair_lock 、pthread_mutex是典型的互斥锁,在没有获取到锁时既锁已经被添加,还没有被解开时.
它们都会让当前线程进入休眠状态既不占用CPU资源,但是为什么,互斥锁比自旋锁的效率低呢,是因为休眠,以及唤醒休眠,比忙等更加消耗CPU资源.
NSLock 封装的pthread_mutex的PTHREAD_MUTEX_NORMAL 模式
NSRecursiveLock 封装的pthread_mutex的PTHREAD_MUTEX_RECURSIVE 模式
3、条件锁
在一定条件下,让其等待休眠,并放开锁,等接收到信号或者广播,会从新唤起线程,并重新加锁.
pthread_cond_wait(&_cond, &_mutex); // 信号 pthread_cond_signal(&_cond); // 广播 pthread_cond_broadcast(&_cond); 像NSCondition封装了pthread_mutex的以上几个函数,NSConditionLock封装了NSCondition
4、递归锁
递归锁的主要意思是,同一条线程可以加多把锁.什么意思呢,就是相同的线程访问一段代码,如果是加锁的可以继续加锁,继续往下走,不同线程来访问这段代码时,发现有锁要等待所有锁解开之后才可以继续往下走.
NSRecursiveLock 封装的pthread_mutex 的PTHREAD_MUTEX_RECURSIVE模式