GCD源码分析

最近的项目中一直有关于多线程网络请求的需求,所以一直在使用GCD队列处理问题,闲置下来,整理一下思路,研读了一次GCD的内部实现。
Dispatch Queue
Dispatch Queue 对于我们开发者来说应该是非常熟悉了,运用的场景非常之多,但是他的内部是如何实现的呢?

  • 用于管理追加的Block的C语言层实现的FIFO队列
  • Atomic函数中实现的用于排他控制的轻量级信号
  • 用于管理线程的C语言层实现的一些容器
    不难想象,GCD的实现需要使用以上这些工具,但是如果仅用这些内容便可实现,那么就不需要内核级实现了。(实际上在一般的Linux内核中可能使用面向Linux操作系统而移植的GCD)。
    甚至有人会想,只要努力编写线程管理的代码,就根本用不到GCD,是这样的吗?
    我们先来回顾一下苹果的官方说明:
    通常,应用程序中编写的线程管理用的代码要在系统级实现。
    实际上正如这句话所说,在系统级即iOS和OS X的核心XNU内核级上实现,因此无论编程人员如何努力编写管理线程的代码,在性能方面也不可能胜过XNU内核级所实现的GCD。
    使用GCD要比使用pthreads和NSThread这些一般的多线程编程API更好。并且,如果用GCD就不必编写为操作线程反复出现的类似的源代码(这里被称为固定源代码片段),而可以在线程中集中实现处理内容,真的是好处多多。我们尽量多使用GCD或者使用了Cocoa框架GCD的NSOperationQueue类等API。
    编程人员所使用GCD的API全部包含在libdispatch库的C语言函数。Dispatch Queue通过结构体和链表,被实现为FIFO队列。FIFO队列主要是负责管理通过dispatch_async等函数所追加的一系列Blocks。所以我们可以理解为一旦我们在程序中由上到下追加了一组Blocks,那么排除掉dispatch_after,其内部的追加过程是一个先进先出原则。
    但是Block本身并不是直接加入到这个FIFO队列中,而是先加入Dispatch Continuation这一dispatch_continuation_t类型结构体中,然后再进入FIFO队列。该结构体用于记忆Block所属的Dispatch Group和其他一些信息,相当于一般常说的执行上下文(execution context)。
    Dispatch Queue可通过dipatch_set_target_queue函数设定,可以设定执行该Dispatch Queue处理的Dispatch Queue为目标。该目标可像串珠子一样,设定多个连接在一起的Dispatch Queue,但是在连接串的最后必须设定为Main Dispatch Queue,或各种优先级的Global Dispatch Queue,或是准备用于Serial Dispatch Queue的各种优先级的Global Dispatch Queue。
    Main Dispatch Queue 在RunLoop中执行Block。这并不是令人耳目一新的新技术。
    Global Dispatch Queue有如下8种:
    Global Dispatch Queue (High priority)
    Global Dispatch Queue (Default priority)
    Global Dispatch Queue (Low priority)
    Global Dispatch Queue (Background priority)
    Global Dispatch Queue (High overcommit priority)
    Global Dispatch Queue (Default overcommit priority)
    Global Dispatch Queue (Low overcommit priority)
    Global Dispatch Queue (Background overcommit priority)
    注意前面四种 和后面四种不同优先级的Queue有一词之差:Overcommit。其区别就在于Overcommit Queue不管系统状态如何都会强制生成线程队列。
    这8种Global Dispatch Queue 各使用一个pthread_workqueue。GCD初始化时,使用pthread_workqueue_create_np函数生成pthread_wrokqueue。
    pthread_wrokqueue包含在Libc提供的pthreads API中。它通过系统的bsdthread_register和workq_open函数调用,在初始化XNU内核的workqueue之后获取其信息。
    XNU内核有4种workqueue:
    WORKQUEUE_HIGH_PRIOQUEUE
    WORKQUEUE_DEFAULT_PRIOQUEUE
    WORKQUEUE_LOW_PRIOQUEUE
    WORKQUEUE_BG_PRIOQUEUE

以上为4种执行优先级的workqueue。该执行优先级与Global Dispatch Queue的4种执行优先级相同。
下面看一下Dispatch Queue中执行Block的过程。当在Global Dispatch Queue 中执行Block时,libdispatch 从Global Dispatch Queue自身的FIFO队列取出Dispatch Continuation,调用pthread_workqueue_additem_np函数。将该Global Dispatch Queue 本身、符合其优先级的workqueue信息以及执行Dispatch Continuation的回调函数等传递给参数。

pthread_workqueue_additem_np函数使用workq_kernreturn系统调用,通知workqueue增加应当执行的项目。根据该通知,XNU内核基于系统状态判断是否要生成线程。如果是Overcommit优先级的Global Dispatch Queue ,workqueue则始终生成线程。
该线程虽然与iOS和OS X中通常使用的线程大致相同,但是有一部分pthread API不能使用。详细信息可以参考苹果的官方文档《并发编程指南》的“Compatibility with POSIX Threads“这一章节。
另外,因为workqueue生成的线程在实现用于workqueue的线程计划表中运行,他的上下文切换(shift context)与普通的线程有很大的不同。这也是我们使用GCD的原因。
workqueue的线程执行pthread_workqueue函数,该函数调用libdispatch的回调函数。在该回调函数中执行加入到Global Dispatch Queue中的下一个Block。
以上就是Dispatch Queue执行的大概过程。
由此可知,在编程人员自己编写的线程管理代码中想发挥出原生GCD的性能是不可能的。

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

推荐阅读更多精彩内容