iOS中的锁 笔记
<u>会阻塞线程的锁,都属于互斥锁</u>
NSLock
NSLock的lock方法和lockBeforeDate: 方法会阻塞线程;tryLock方法不会阻塞线程。
多个线程同时加锁时,其他请求锁的线程按照先进先出执行。
NSConditionLock
NSConditionLock与NSLock行为相似,只不过可以设置条件(condition整数),可以设置为在满足condition时才进行lockWithCondition:、unlockWithCondition:、tryLockWithCondition: 等操作(当然也可以不设置条件)。
故可以使用NSConditionLock设置线程(任务)间的依赖关系,用GCD可以结合着使用进行实现。
NSRecursiveLock
递归锁。可以在单个线程中返回加锁或解锁,其自身会记录加锁和解锁的次数,只有次数匹配时,才会真正的解锁,其他线程才可以加锁成功。
NSLock、NSConditionLock和NSRecursiveLock是先轮询,之后再进入waiting状态。
NSCondition
NSCondition由 一个锁 + 条件检查器 组成。在每个线程中,都可以对condition对象单独进行lock和unlock,不影响其他线程再次加锁或解锁。
condition对象调用wait后,直接进入waiting状态,阻塞当前线程执行。等待其他线程对condition调用signal 或 broadcast 后,唤醒1个或所有的waiting线程,继续向下执行。
以上四种锁都是遵循NSLocking协议。
@synchronized
@synchronized同步锁会将指定的参数对象进行加锁。只有对相同对象进行加锁时,后加锁的线程才会被阻塞。否则无效。
dispatch_semaphore
信号量是GCD进行同步的一种方式。
通过dispatch_semaphore_create创建信号量(指定信号值,即同时执行的任务数)。dispatch_semaphore_wait函数会对信号值进行检测:当信号值大于1时,信号值减1,继续向下执行任务,在信号值是1的信号量中,相当于加锁操作;当信号值为0时,调用线程被阻塞。只有当其他线程调用dispatch_semaphpre_signal进行信号恢复后(保证信号值重新大于0),被阻塞的线程继续向下执行。
**dispatch_semaphore与NSCondition都是基于信号的锁,区别是信号量会保存发送的信号,NSCondition则不可以(只能signal)。
OSSpinLock
自旋锁现在已经不建议使用了,具体原因见上面(优先级反转造成死锁)。
苹果推荐使用<os/lock.h>中的os_unfair_lock() 锁替代。
自旋锁与互斥锁都是抢占式,任何时候都只能有一个保持者。区别是:互斥锁中,调用者在别的运算单元抢占锁后进入睡眠,等待结束后被唤醒进行抢占;自旋锁,调用者在被运算单元抢占锁后不睡眠,循环查看自旋锁是否被释放。
故自旋锁适合保持锁时间较短的情况,这种情况下其效率远高于互斥锁。
缺点:需要获取锁的线程优先级相同。如果低优先级的线程获得锁后,高优先级线程会处于busy-wait状态,占用大量CPU。而低优先级线程无法获取CPU时间,导致任务无法完成,也就无法释放锁。造成死锁(优先级反转)。
参考资料: