这是我参与8月更文挑战的第28天,活动详情查看: 8月更文挑战
NSConditionLock分析
汇编分析NSConditionLock创建
接下来,我们来分析一下NSConditionLock锁的执行:
解析:
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:2];中的2相当于一个匹配条件;设置为2,也就是说lockWhenCondition为2的先执行;所以先打印线程2;- 打印
线程2之后,由于[conditionLock unlockWithCondition:1];将匹配条件改为了1,所以在执行1条件的任务,也就是打印线程1; - 由于打印
线程3的任务没有设置匹配条件,就是一个普通的加锁,缺少条件控制,所以不需要匹配,会先执行,打印线程3; - 所以最终打印结果
线程3,线程2,线程1依次打印;
这个时候我们发现NSConditionLock的执行和NSCondition十分相似,都有条件控制;那么我们就不免有些疑问?
NSConditionLock和NSCondition有什么关系呢- 初始化时传入的条件
2又是什么东西呢? lockWhenCondition又是如何进行条件控制的呢?unlockWithCondition又做了什么呢?
接下来,我们分别在这四处有疑问的地方打上断点:
按照以往的经验,如果我们想要研究initWithCondition:2的操作,那么我们可以添加initWithCondition的符号断点:
但是我们继续执行代码之后发现,initWithCondition符号断点并没有被拦截到:
这是因为,此处的符号断点不能单纯的设置为initWithCondition,而是应该设置-[NSConditionLock initWithCondition:],我们修改符号断点,然后重新执行查看结果:
成功拦截到符号断点!接下来我们看一下寄存器中的情况:
x0为默认参数,消息的接收者:NSConditionLock;x1为默认参数,SEL:initWithCondition:;x2为方法的参数:2;
接下来,我们通过汇编代码来分析执行的流程,细枝末节我们可以忽略,那么分析流程的话,我们就只需要关注bl和return指令的执行,因为bl是跳转指令,会有相关的处理,而return;指令会直接返回;我们把所有的bl指令都打上断点,然后继续向下执行,分析NSConditionLock的initWithCondition:方法的执行流程:
此时一个未知的
对象,调用了init方法,并传递了参数2;[? init:2]
继续执行:
NSConditionLock对象调用了init方法,并传递了参数2;-[NSConditionLock init:2](NSConditionLock初始化)
继续执行:
NSConditionLock对象调用了zone方法;-[NSConditionLock zone](内存开辟)
继续执行:
NSCondition调用了allocWithZone:方法;+[NSCondition allocWithZone:]
继续执行:
NSCondition对象调用了init方法;-[NSCondition init]
继续执行:
此时执行到了
return方法,因为返回值放在了x0寄存器;打印x0发现返回了NSConditionLock对象,并且condition为2;
-[NSConditionLock initWithCondition:]方法到此处已经return;至此,内存开辟和成员变量的处理已经结束;我们可以通过控制台查看一下内存:
0x01000001ffe44209为isa;<NSCondition: 0x28340c000>和我们前边汇编中查看到的创建的NSCondition地址一致;<NSCondition: 0x28340c000>成为了<NSConditionLock: 0x2808400f0>的成员变量;
没有看到2,可以继续扩大查看的内存:
我们看到了2的地址;
至此,我们可以大致分析出-[NSConditionLock initWithCondition:]方法的实现:
- 1、
[? init:2] - 2、
-[NSConditionLock init:2] - 3、
-[NSConditionLock zone] - 4、
+[NSCondition allocWithZone:] - 5、
-[NSCondition init]
在
-[NSConditionLock initWithCondition:]中,封装了一个NSCondition
但是lockWhenCondition与unlockWithCondition方法是怎么进行控制的,我们依然不得而知;
lockWhenCondition与unlockWithCondition分析
接下来,我们分析lockWhenCondition和unlockWithCondition,那么就需要添加符号断点-[NSConditionLock lockWhenCondition:]和-[NSConditionLock unlockWithCondition:]
lockWhenCondition分析
接下来,我们依然研究bl指令的执行:
NSDate调用了distantFuture方法;
需要注意的是,因为我们是多线程操作,所以我们要注意左侧的线程,我们目前是Thread 7,我们尽量在当前的线程中分析,避免分析到其他线程的逻辑;
继续执行到指令b:
调用了
-[NSConditionLock lockWhenCondition:beforeDate:]方法,这个方法有两个参数,意味着我们还需要看一下x3寄存器
从名字_NSConstantDateDistantFuture上我们推测,第二个参数极有可能是NSDate调用了distantFuture的返回值
我们此时,添加符号断点-[NSConditionLock lockWhenCondition:beforeDate:],进入此方法:
其第二个参数值为1;
继续下一个bl指令:
调用了
-[NSCondition lock]方法
继续向下执行(步骤过多,分析类似,我们挑主要的分析):
调用了
-[NSCondition waitUntilDate]方法,进入等待;
接下来就会跳转到其他线程做操作,此部分我们不分析;再次回来的时候:
调用了
unlock方法,并且返回1,也就是true;表示此刻不再等待;
-[NSConditionLock lockWhenCondition]代码大致流程为:
- 1、
+[NSDate distantFuture] - 2、
-[NSConditionLock lockWhenCondition:beforeDate:]- 2.1、
-[NSCondition lock] - 2.2、
-[NSCondition waitUntilDate] - 2.3、
unlock
- 2.1、
接下里分析unlockWithCondition;
unlockWithCondition分析
调用了
-[NSCondition lock]方法(加锁)
继续执行:
调用了
-[NSCondition broadcast]方法(广播)
调用了
-[NSCondition unlock]方法(解锁)
-[NSConditionLock unlockWithCondition]代码大致流程为:
- 1、
-[NSCondition lock] - 2、
-[NSCondition broadcast] - 3、
-[NSCondition unlock]
源码对比
因为我们看的是swift版的,所以代码会有些差异,我会直接在代码中进行注释对应的代码;
- NSConditionLock初始化
- lockWhenCondition
- unlockWithCondition
通过源码与我们通过汇编分析出的代码逻辑对比,基本上主要流程都能够分析出来,这也就是我们分析底层源码的一种方式:在未开源的情况下,我们依旧能够通过汇编大致推算出底层代码的实现逻辑;