这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战
iOS 开发,各种锁你了解多少?NSLock、NSCondtion、NSRecursiveLock…….
回顾
在上篇博客中已经对NSLock、NSCondtion、NSRecursiveLock、NSCondition等锁进行了举例分析,那么本篇博客就继续分析锁,从Foundation源码分析锁!
iOS底层探索之多线程(六)—GCD源码分析(sync 同步函数、async 异步函数)
iOS底层探索之多线程(八)—GCD源码分析(函数的同步性、异步性、单例)
iOS底层探索之多线程(十四)—关于@synchronized锁你了解多少?
iOS底层探索之多线程(十五)—@synchronized源码分析
iOS底层探索之多线程(十六)——锁分析(NSLock、NSCondtion、NSRecursiveLock、NSCondition)
1. 从Foundation源码分析锁
上篇博客对NSLock、NSCondtion、NSRecursiveLock等锁的使用,进行了代码的举例和分析,那么他们其实都是对pthread锁进行了一层封装。通过查看 NSLock的 API,发现是在Foundation 框架下的如图:

通过查看 API 发现,锁都是遵循了一个叫做NSLocking的协议,所以大部分锁都是有如下两个方法的:
@protocol NSLocking
- (void)lock;
- (void)unlock;
@end
复制代码但是
OC的Foundation框架是不开源的,那难道我们的探索就止步于此了吗?有没有其他的方式来探索呢?
有的,我们可以通过 swift 的Foundation 框架的开源源码来看看锁是如何封装实现的,说干就干!?源码戳这里
- NSLock

从 swift 的Foundation 的源码工程中搜索NSLocking协议,发现这里针对不同的平台进行了一些设置和初始化工作,很明显可以看出来是对pthread的封装。
还有构造方法(init)、析构方法(deinit)、加锁(lock)、解锁(unlock)的方法定义,如下:

- 构造方法init()就是调用了pthread的pthread_mutex_init(mutex, nil)方法
- 析构方法deinit就是调用了pthread的pthread_mutex_destroy(mutex)方法
- 加锁方法 lock()就是调用了pthread的pthread_mutex_lock(mutex)方法
- 解锁方法 unlock()就是调用了pthread的pthread_mutex_unlock(mutex)方法
通过NSLock和NSRecursiveLock方法的对比,发现它们的lock()方法都是一样的,都调用了pthread_mutex_lock(mutex),如下:
- NSRecursiveLock

那为什么
NSRecursiveLock就可以支持可递归加锁呢?why ?为什么呢!请继续往下看:

NSRecursiveLock方法支持可递归加锁,原因就是图中所示,在init方法中,通过pthread_mutexattr_settype(attrs, Int32(PTHREAD_MUTEX_RECURSIVE))进行了递归的设置,这一波操作真是很细节,非常的人性化的设计,着实到位?(ps:哈哈)
- NSCondition

通过搜索,发现NSCondition方法也是对pthread进行了封装,就是多了个对 cond的处理,除了进行pthread_mutex互斥处理外,还对pthread_cond进行了处理,同时提供了wait、signal、broadcase等方法,如下图所示:

- NSConditionLock

NSConditionLock方法,里面没有直接对进行pthread_mutex进行封装,只是属性里面使用了NSCondition类型的_cond属性和一个_swift_CFThreadRef类型的属性,通过这两个属性,实现加锁和线程方面的相关处理。
- NSCondition里面是包含了对- pthread_mutex的封装
- _swift_CFThreadRef其实是等于- pthread_t

2. NSLocationLock分析
先来看看下面?的代码,猜猜打印的顺序:
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:2];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        [conditionLock lockWhenCondition:1];
        NSLog(@"线程 1");
        [conditionLock unlockWithCondition:0];
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        [conditionLock lockWhenCondition:2];
        sleep(0.1);
        NSLog(@"线程 2");
        [conditionLock unlockWithCondition:1];
    });
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
       [conditionLock lock];
       NSLog(@"线程 3");
       [conditionLock unlock];
    });
复制代码- 代码运行结果

这里
线程 2一定比线程 1先执行,因为NSConditionLock锁,⼀旦⼀个线程获得锁,其他线程⼀定会等待,在初始化的时候设置了条件2,所以线程 2的优先级高于线程 1。
- [xxxx lock]:表示- xxx期待获得锁,如果没有其他线程获得锁(不需要判断内部的- condition) 那它能执⾏此⾏以下代码,如果已经有其他线程获得锁(可能是条件锁,或者⽆条件锁),则等待,直⾄其他线程- 解锁
- [xxx lockWhenCondition:A条件]:表示如果没有其他线程获得该锁,但是该锁内部的- condition不等于- A条件,它依然不能获得锁,仍然等待。如果内部的- condition等于- A条件,并且没有其他线程获得该锁,则进⼊代码区,同时设置它获得该锁,其他任何线程都将等待它代码的完成,直⾄它解锁。
- [xxx unlockWithCondition:A条件]: 表示释放锁,同时把内部的- condition设置为- A条件
- return = [xxx lockWhenCondition:A条件 beforeDate:A时间]:表示如果被锁定(没获得锁),并超过该时间则不再- 阻塞线程。但是- 注意:返回的值是- NO,它没有改变锁的状态,这个函数的⽬的在于可以实现两种状态下的处理
- 所谓的condition就是整数,内部通过整数⽐较条件
- 线程 1调⽤- [NSConditionLock lockWhenCondition:],此时此刻因为不满⾜当前条件,所以会进⼊- waiting状态,当前进⼊到- waiting时,会释放当前的互斥锁。
- 此时当前的线程 3调⽤[NSConditionLock lock:],本质上是调⽤[NSConditionLock lockBeforeDate:],这⾥不需要⽐对条件值,所以线程 3会打印。
- 接下来线程 2执⾏[NSConditionLock lockWhenCondition:],因为满⾜条件值,所以线程2会打印,打印完成后会调⽤[NSConditionLock unlockWithCondition:],这个时候把value设置为1,并发送boradcast, 此时线程 1接收到当前的信号,唤醒执⾏并打印。
- ⾃此当前打印为 线程 3–>线程 2–>线程 1。
- [NSConditionLock lockWhenCondition:]:这⾥会根据传⼊的- condition值和- value值进⾏对⽐,如果不相等,这⾥就会阻塞,进⼊线程池,否则的话就继续代码执⾏。
- [NSConditionLock unlockWithCondition:]: 这⾥会先更改当前的- value值,然后进⾏⼴播,唤醒当前的线程。
3.总结
- 以上的锁,其实都是对pthread封装,你如果对pthread比较熟悉,能直接用就直接用,不能就用这些封装的就可以
- 使用锁的时候,根据自己的业务场景来合理的使用互斥锁、递归锁、条件锁
更多内容持续更新 ?下篇分析,读写锁,敬请期待!
? 喜欢就点个赞吧??
? 觉得有收获的,可以来一波,收藏+关注,评论 + 转发,以免你下次找不到我??
?欢迎大家留言交流,批评指正,互相学习?,提升自我?

























![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)
