关键词:
回顾
在上篇博客已经介绍了各种队列和异步、同步函数的组合,GCD
的队列和函数,对队列和任务的执行有了清晰的认识, 那么本篇博客将继续介绍GCD
的队列和源码分析。
1. 主队列分析
查看主队列的api
如下图:
- 主队列是一个特殊的串行队列
- 主队列在调用
main()
函数之前自动创建的。 - 主队列在应用程序上下文中用于与主线程和main runloop 交互。
那么断点在
main
函数处去验证一下
通过断点,确实验证了主队列是在调用
main()
函数之前自动创建的。
那么我们要看底层源码,该怎么看啊,首先我们得知道 GCD
是属于哪个源码的,才能进一步去探索分析。
-
再次通过断点寻找,如下图
通过bt
打印堆栈信息,可以定位到libdispatch.dylib
动态库,那么就去苹果开源网站去下载源码试试。 -
下载libdispatch.dylib源码,探索
GCD
。
-
libdispatch
源码
libdispatch
源码比较难受 -
注释非常的少
-
宏定义非常的多
-
函数名非常的长
这是一个硬骨头,非常的不好啃,只能硬着头皮慢慢啃了,难受啊!
- 源码搜索
dispatch_get_main_queue
dispatch_get_main_queue
是通过DISPATCH_GLOBAL_OBJECT
返回的,是一个宏定义
DISPATCH_GLOBAL_OBJECT
- 通过
_dispatch_main_q
参数搜索
dispatch_get_main_queue(void)
return DISPATCH_GLOBAL_OBJECT(dispatch_queue_main_t, _dispatch_main_q);
- 还可以通过主队列的
dq_label
搜索如下:
在源码中有dq_serialnum = 1
,这是不是意味着可以作为主队列
就是 串行队列
的依据呢? 现在还不得而知,那么去看看串行队列底层是怎么实现的,或许可以找到答案!
- 主队列的初始化是在
dispatch_init()
方法中?
- 在
dispatch_init()
中成功找到了主队列初始化的地方, - 获取默认队列,
- 并将主队列地址绑定到当前队列和主线程中
2. 串行、并发队列分析
串行队列
和并发队列
都通过dispatch_queue_create
创建的,那么去搜索一下
通过搜索定位到dispatch_queue_create
,在通过返回的是_dispatch_lane_create_with_target
,再继续搜索
- 代码比较长,从返回值看,再推导
_dispatch_object_alloc
申请内存空间_dispatch_queue_init
构造函数初始化- 判断是否为并发队列,如果是,传入
DISPATCH_QUEUE_WIDTH_MAX
,否则传入1
。也就是说,串行队列这里传入1
,如果是并发队列,则传入DISPATCH_QUEUE_WIDTH_MAX
- 对
dq
进行设置,如dq_label
、dq_priority
等
_dispatch_queue_init
- 把前面的
width
传进来,赋值dqf |= DQF_WIDTH(width)
DQF_WIDTH(width)
,也就是用来确定队列的类型,以此来区分串行队列
和并发队列
其他参数vtable
、dqai
,分别是什么呢?继续探索
dqai
初始化
在开头有这么一句代码
// dqai 创建 - dqa传入的属性串行还是并行
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);
-
_dispatch_queue_attr_to_info
在这里进行初始化了dqai
,并判断dqa
的类型,如果是并发队列
,则设置并发队列
为true
,否则默认为串行队列
。在调用_dispatch_queue_init
对dq
进行构造时,对队列类型进行了区分,也就是DQF_WIDTH(width)
的传参,串行队列width=1
,否则为并发队列
。 -
vtable
const void *vtable; // - 设置类 类是通过宏定义拼接而成
if (dqai.dqai_concurrent)
// OS_dispatch_##name##_class
// OS_dispatch_queue_concurrent - 宏定义拼接类类型
vtable = DISPATCH_VTABLE(queue_concurrent);
else
vtable = DISPATCH_VTABLE(queue_serial);
vtable
可以理解为是一个类,或者说构造队列的模板类,qai
来区分队列的类型,根据队列的类型来初始化不同的vtable
。DISPATCH_VTABLE
是一个宏定义的方法,全局搜索DISPATCH_VTABLE
的定义
// DISPATCH_VTABLE定义
#define DISPATCH_VTABLE(name) DISPATCH_OBJC_CLASS(name)
// vtable symbols - 模板
#define DISPATCH_OBJC_CLASS(name) (&DISPATCH_CLASS_SYMBOL(name))
// 拼接形成类
#define DISPATCH_CLASS_SYMBOL(name) OS_dispatch_##name##_class
DISPATCH_VTABLE
函数的传参根据不同的队列类型传参不一致。
并发队列
传queue_concurrent
参数,最终拼接后,队列类型对应的类为:OS_dispatch_queue_concurrent
串行队列
传queue_serial
参数,最终拼接后,队列类型对应的类为:OS_dispatch_queue_serial
所以vtable
对应的就是队列的类型
。通过拼接完成类的定义,这和我们在应用层使用的队列类型是一致的。
3. 全局队列分析
进入
dispatch_get_global_queue
的api
- 创建全局并发队列时可以传参数
- 根据不同服务质量或者优先等级提供不同的并发队列。
通过全局队列的标识 在源码里面搜索🔍
- 系统会维护一个
全局队列集合
, - 根据不同的
服务质量
或者优先等级
提供不同的全局队列
。 - 我们在开发工作中默认使用:
dispatch_get_global_queue(0, 0)
。
更多内容持续更新
🌹 喜欢就点个赞吧👍🌹
🌹 觉得有收获的,可以来一波,收藏+关注,评论 + 转发,以免你下次找不到我😁🌹
🌹欢迎大家留言交流,批评指正,互相学习😁,提升自我🌹
ios底层探索之多线程—gcd源码分析(函数的同步性异步性单例)(代码片段)
...博客已经对GCD的sync同步函数产生死锁的情况,进行了底层的源码探索分析,那么本篇博客继续源码的探索分析!iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初... 查看详情
ios底层探索之多线程(十五)—@synchronized源码分析(代码片段)
...f;对于锁你又了解多少?锁的原理你又知道吗?iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识GCDiOS底层探索之多线程(四)—GCD的队列iOS底层探索之多线程(五)—GCD... 查看详情
ios底层探索之多线程—gcd源码分析(事件源dispatch_source)(代码片段)
...博客已经对GCD的调度组做了介绍和举例应用,还有对底层源码的分析,那么本篇博客将对事件源dispatch_source进行分析!iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)... 查看详情
ios底层探索之多线程—gcd源码分析(信号量dispatch_semaphore_t)(代码片段)
...栅栏函数做了一个基本介绍,还有应用的举例并且对底层源码进行了分析,本篇博客将对信号量进行探索分析!iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识... 查看详情
ios底层探索之多线程(十四)—关于@synchronized锁你了解多少?(代码片段)
...f;对于锁你又了解多少?锁的原理你又知道吗?iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识GCDiOS底层探索之多线程(四)—GCD的队列iOS底层探索之多线程(五)—GCD... 查看详情
ios底层探索之多线程(十三)—锁的种类你知多少?(代码片段)
...#xff1f;从本篇博客开始将对锁的相关内容进行分析!iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识GCDiOS底层探索之多线程(四)—GCD的队列iOS底层探索之多线程(五)—GCD... 查看详情
ios底层探索之多线程—gcd源码分析(sync同步函数async异步函数)(代码片段)
回顾在上篇博客对GCD的不同的队列继续了底层的源码探索分析,那么本篇博客将继续对GCD的函数继续源码分析。1.sync同步函数我们都知道GCD底层是用C写的,封装了block函数来执行添加的任务,那么这个block底层是如何... 查看详情
ios底层探索之多线程—gcd的队列(代码片段)
...的认识,那么本篇博客将继续介绍GCD的相关知识。iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁iOS底层探索之多线程(三)—初识GCD1.不同队列举例主队列添加同步任务看看下面这个例子🌰//主队... 查看详情
ios底层探索之多线程—gcd源码分析(调度组)(代码片段)
...已经对GCD的信号量做了一个介绍和举例应用,还有对底层源码的分析,那么本篇博客看苹果工程师,如何巧妙封装调度组,看完底层源码直呼好家伙,真是妙啊!!!iOS底层探索之多线程(一)—进程... 查看详情
ios底层探索之多线程—gcd源码分析(死锁的原因)(代码片段)
回顾在上篇博客已经对GCD的sync同步函数、async异步函数进行了源码的分析,那么本篇博客继续源码的探索分析!1.补充sync和async的区别是否可以开启新的线程执行任务任务的回调是否具有异步行、同步性是否产生死锁问题... 查看详情
ios开发底层之多线程探索-19(代码片段)
文章目录前言一、进程与线程?1.进程2.线程3.进程与线程的关系二、多线程1.多线程优点2.多线程缺点3.线程的生命周期4.线程池的饱和策略RejectedExecutionHandler接口5.优先级翻转(IOvccpu优先级提升)6.优先级的影响因素三.多线程下... 查看详情
ios开发底层之多线程探索-19(代码片段)
文章目录前言一、进程与线程?1.进程2.线程3.进程与线程的关系二、多线程1.多线程优点2.多线程缺点3.线程的生命周期4.线程池的饱和策略RejectedExecutionHandler接口5.优先级翻转(IOvccpu优先级提升)6.优先级的影响因素三.多线程下... 查看详情
ios底层探索之多线程—初识gcd(代码片段)
...用最多的还是GCD,那么从本篇开始讲陆续介绍GCD。iOS底层探索之多线程(一)—进程和线程iOS底层探索之多线程(二)—线程和锁1.什么是GCDGCD定义GrandCenterDispatch简称GCD,是苹果公司开发的技 查看详情
ios底层探索之多线程(十七)——通过swift的foundation源码分析锁(nslocknsconditionnsrecursivelock)(代码片段)
...篇博客就继续分析锁,从Foundation源码分析锁!iOS底层探索之多线程(一)—进程和线程 查看详情
ios底层探索之多线程(十六)——锁分析(nslocknscondtionnsrecursivelocknscondition)(代码片段)
...绍,那么本篇博客就分析一下其他的一些锁!iOS底层探索之多线程(一)— 查看详情
ios开发底层之多线程探索-19(代码片段)
文章目录前言一、进程与线程?1.进程2.线程3.进程与线程的关系二、多线程1.多线程优点2.多线程缺点3.线程的生命周期4.线程池的饱和策略RejectedExecutionHandler接口5.优先级翻转(IOvccpu优先级提升)6.优先级的影响因素三.多线程下... 查看详情
ios底层探索之多线程—进程和线程(代码片段)
前言在iOS的面试中多线程是经常被问到的,多线程也是一个难点,很多面试者平时用的不多,因此很难回答到点子上,那么本篇博客就对多线程进行探索和分析。1.进程和线程什么是进程进程是指在系统中正在运... 查看详情
ios底层探索之多线程(十八)——锁篇章的完结篇(手把手两种方式带你实现一个读写锁!)(代码片段)
...,那么本篇博将手把手带你实现一个读写锁!iOS底层探索之多线程(一)—进程和线程iOS 查看详情