GCD源码的分析

最近看了苹果 libdispatch 的源码,也就是 GCD 的源码,对于 GCD 的运作方式有一定了解和自己的见解。我看的 libdispatch 并不是苹果最新版本的源码,但按道理来说 GCD 的运作逻辑应该不会很大的改变,细节方面是有所改变的,但并不影响我们对 GCD 的运作机制的了解。这里是 GCD 的源码:libdispatch源码

首先来说一下 GCD 中用到的数据类型,在 base.h 文件中有所提到:


GCD 数据结构

上图展示了 GCD 的所需数据类型的结构,我讲述一下这些数据类型干什么用的:

_do: 这个是 dispatch_object_s * 结构体,这个是 GCD 的基类,GCD 数据结构都是由这个结构体搭建起来的。

_dc: 这个是任务类型,通常 dispatch_async 内的 block 最终都会封装成这个数据类型。

_dq: 这个是任务队列,我们创建的对列都是这个类型的,不管是串行队列还是并发队列。

_dqa: 这个是任务队列的属性,任务队列的属性里面包含了任务队列里面的一些操作函数,可以表明这个任务队列是串行还是并发队列。

_ds: 这个是 GCD 的 sourece ,可以监测内核事件,文件读写事件和 socket 通信事件等。

_dsa: sourece 的属性。

_dsema: 信号量,如果了解过 pthread 都知道,信号量可以用来调度线程。

dispatch_object_t 是一个联合体,所以当用 dispatch_object_t 可以代表这个结合体内的所有数据类型。

接下来详细说明一下 dispatch_object_s 内的结构是怎么样的(大家也可以阅读这篇文章:变态的libDispatch结构分析-object结构 - 爱悠闲):



从上两图可以清晰的了解到 dispatch_object_s 的结构,这里讲解一下,这个结构体内的一些数据的作用:

dispatch_object_s 最前面有一个 vtable 的结构体,这个结构体内包含了这个 dispatch_object_s 的操作函数,vtable内的数据结构的解析:

do_type:这个 dispatch_object_s 的类型。

do_kined:说明这个 dispatch_object_s 。

do_debug:debug 方法。

do_invoke: 唤醒队列的方法。

do_dispose:销毁队列的方法,通常内部会调用 这个对象的 finalizer 函数。

do_probe:这个方法很重要,用户创建的队列这个方法是空的,但 rootqueue 内的这个有一个 _dispatch_queue_wakeup_global 函数,这是个很重要的函数。

上面大体是 vtable 内的数据,其余的是:

do_next:链表的 next 。

do_ref_cnt:引用计数。

do_ref_xcnt:外部引用计数。(这两个是用来内存管理的,这里探究 GCD 的机制,我也就没多搞清楚这两个是怎么用的)

do_suspend_cnt:suspend计数,用作暂停标志,比如延时处理的任务,设置该引用计数之后;在任务到时后,计时器处理将会将该标志位修改,然后唤醒队列调度。

dispatch_queue_s:目标队列,就是当前这个struct x在哪个队列运行。

do_ctext:上下文,我们要传递的参数。

下面说一下,了解 GCD 所需要的知识:

在程序运行的时候,GCD 会初始化 六个 rootqueue 和 一个 mainqueue,这六个 rootqueue 有低中高三种优先级,这些 rootqueue 主要是用来调度任务,我们自己创建的队列其实并不能调配任务,因为我们创建的队列的 do_probe 都是空的,我自己创建的队列都是链接在 rootqueue 下的,利用 rootqueue 来调配任务,所以我也建议不要使用 GCD 创建队列,这样会使内部处理更加复杂,这个以后详细说明。 mianqueue 是要绑定在 UI 线程的,用来更新界面的,mainqueue 是一种串行队列。 mianqueue 在用户层彰显的就是 dispatch_get_main_queue(),而 rootqueue 彰显的是 dispatch_get_global_queue 。下面讲解一下 dispatch_queue_s 的结构是怎么样的:


上图可以看出,dispatch_queue_s 和 dispatch_object_s 差别在于 dispatch_queue_s 多了DISPATCH_QUEUE_HEADER 和 dq_label[DISPATCH_QUEUE_MIN_LABEL_SIZE],我们从中也可以看出,我们队列起名要少于64个字符,DISPATCH_QUEUE_HEADER 内的内容有:

dq_running: 队列正在运行的任务数。

dq_width: 队列的宽度(串行队列为1,并发队列应该大于1)。

dq_item_tail: 指向这个队列的尾节点。

dq_item_head: 指向这个队列的头节点。

dq_serialnum: 不知道干什么的。。。。

dq_finalizer_ctxt: 结束函数的的上下文(参数)。

dq_finalizer_func: 结束函数。

可以看一下一开始初始化的6个 rootqueue 和 mainqueue 的内容:



上图展示 6个 rootqueue 和 mianqueue 的具体内容,主要讲一下里面重要的,在 rootqueue 里面 重要的是 do_vtable 内的do_provbe 的函数是什么,截图一下:


可以看出 rootsueu 的函数是 _dispatch_queue_wakeup_global,这个很重要。

在 libdispatch 里面有一些原子操作函数,这些函数都是由汇编写成的,效率很高,而且不会被其他线程干扰,这里说明一下一些原子函数的作用:

dispatch_atomic_cmpxchg(A, B, C) : 将 A 和 B对比,相等,则将 C 赋值给 A,返回 YES,否则返回 NO。

dispatch_atomic_xchg(A, C): 将 C 赋值给 A , 返回赋值前的 A 。

dispatch_atomic_inc(A): A 自增1。

dispatch_atomic_dec(A): A 自减1。

dispatch_atomic_add(A, B): A = A + B 。

Adispatch_atomic_sub(A, B): A = A - B 。

dispatch_atomic_or(A, B): A = A | B 。

dispatch_atomic_and(A, B): A = A & B 。

在 GCD 内有一宏定义: _dispatch_hardware_pause(),这个宏定义其实是 asm("pause"),在 __asm__("pause")用法_Linux_IThao123 - IT行业第一站 说明了这个用法的好处,简单说一下,在 x86 架构的 CPU 中,在循环用这个汇编指令,可以保证循环不会被退出且可降低功耗,苹果手机用的是 ARM 指令,用这个汇编指令应该作用不大。

下面的文章将详细分析 GCD 异步执行和同步执行等的实现机制。

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

推荐阅读更多精彩内容