iOS底层探索之多线程(五)—GCD不同队列源码分析

回顾

在上篇博客已经介绍了各种队列和异步、同步函数的组合,GCD的队列和函数,对队列和任务的执行有了清晰的认识, 那么本篇博客将继续介绍GCD的队列和源码分析。

iOS底层探索之多线程(一)—进程和线程

iOS底层探索之多线程(二)—线程和锁

iOS底层探索之多线程(三)—初识GCD

iOS底层探索之多线程(四)—GCD的队列

在这里插入图片描述

1. 主队列分析

查看主队列的api如下图:

dispatch_get_main_queue

  • 主队列是一个特殊的串行队列
  • 主队列在调用main()函数之前自动创建的。
  • 主队列在应用程序上下文中用于与主线程和main runloop 交互。

那么断点在main函数处去验证一下

验证main_queue

通过断点,确实验证了主队列是在调用main()函数之前自动创建的。

那么我们要看底层源码,该怎么看啊,首先我们得知道 GCD是属于哪个源码的,才能进一步去探索分析。

  • 再次通过断点寻找,如下图

    寻找 GCD源码出处

    通过 bt打印堆栈信息,可以定位到libdispatch.dylib动态库,那么就去苹果开源网站去下载源码试试。

  • 下载libdispatch.dylib源码,探索GCD

    libdispatch

  • libdispatch 源码

    GCD源码libdispatch

    libdispatch源码比较难受

  • 注释非常的少

  • 宏定义非常的多

  • 函数名非常的长

这是一个硬骨头,非常的不好啃,只能硬着头皮慢慢啃了,难受啊!

  • 源码搜索dispatch_get_main_queue
    dispatch_get_main_queue

dispatch_get_main_queue是通过DISPATCH_GLOBAL_OBJECT返回的,是一个宏定义

  • 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);
}
_dispatch_main_q
  • 还可以通过主队列的dq_label搜索如下:

在这里插入图片描述

在源码中有dq_serialnum = 1,这是不是意味着可以作为主队列就是 串行队列的依据呢? 现在还不得而知,那么去看看串行队列底层是怎么实现的,或许可以找到答案!

  • 主队列的初始化是在dispatch_init()方法中?
    在这里插入图片描述
  • dispatch_init()中成功找到了主队列初始化的地方,
  • 获取默认队列,
  • 并将主队列地址绑定到当前队列和主线程中

2. 串行、并发队列分析

串行队列并发队列都通过dispatch_queue_create创建的,那么去搜索一下

dispatch_queue_create

通过搜索定位到dispatch_queue_create,在通过返回的是_dispatch_lane_create_with_target,再继续搜索
_dispatch_lane_create_with_target

  • 代码比较长,从返回值看,再推导


    从返回值推导
  • _dispatch_object_alloc申请内存空间
  • _dispatch_queue_init构造函数初始化
  • 判断是否为并发队列,如果是,传入DISPATCH_QUEUE_WIDTH_MAX,否则传入1。也就是说,串行队列这里传入1,如果是并发队列,则传入DISPATCH_QUEUE_WIDTH_MAX
    DISPATCH_QUEUE_WIDTH_MAX
  • dq进行设置,如dq_labeldq_priority

_dispatch_queue_init

在这里插入图片描述

  • 把前面的 width 传进来,赋值dqf |= DQF_WIDTH(width)
  • DQF_WIDTH(width),也就是用来确定队列的类型,以此来区分串行队列并发队列
    DISPATCH_QUEUE_SERIAL_NUMBER_INIT

    其他参数vtabledqai,分别是什么呢?继续探索
    在这里插入图片描述
  • dqai初始化

在开头有这么一句代码

// dqai 创建 - dqa传入的属性串行还是并行
dispatch_queue_attr_info_t dqai = _dispatch_queue_attr_to_info(dqa);

  • _dispatch_queue_attr_to_info

    _dispatch_queue_attr_to_info

    在这里进行初始化了dqai,并判断dqa的类型,如果是并发队列,则设置并发队列true,否则默认为串行队列。在调用_dispatch_queue_initdq进行构造时,对队列类型进行了区分,也就是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来区分队列的类型,根据队列的类型来初始化不同的vtableDISPATCH_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_queueapi

dispatch_get_global_queue
  • 创建全局并发队列时可以传参数
  • 根据不同服务质量或者优先等级提供不同的并发队列。

通过全局队列的标识 在源码里面搜索🔍

全局队列集合
  • 系统会维护一个全局队列集合
  • 根据不同的服务质量或者优先等级提供不同的全局队列
  • 我们在开发工作中默认使用:dispatch_get_global_queue(0, 0)

更多内容持续更新

🌹 喜欢就点个赞吧👍🌹

🌹 觉得有收获的,可以来一波,收藏+关注,评论 + 转发,以免你下次找不到我😁🌹

🌹欢迎大家留言交流,批评指正,互相学习😁,提升自我🌹

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容