GCD源碼的分析

最近看了蘋果 libdispatch 的源碼,也就是 GCD 的源碼,對(duì)于 GCD 的運(yùn)作方式有一定了解和自己的見解。我看的 libdispatch 并不是蘋果最新版本的源碼枣耀,但按道理來說 GCD 的運(yùn)作邏輯應(yīng)該不會(huì)很大的改變拄轻,細(xì)節(jié)方面是有所改變的筏养,但并不影響我們對(duì) GCD 的運(yùn)作機(jī)制的了解。這里是 GCD 的源碼:libdispatch源碼拖陆。

首先來說一下 GCD 中用到的數(shù)據(jù)類型,在 base.h 文件中有所提到:


GCD 數(shù)據(jù)結(jié)構(gòu)

上圖展示了 GCD 的所需數(shù)據(jù)類型的結(jié)構(gòu)依啰,我講述一下這些數(shù)據(jù)類型干什么用的:

_do: 這個(gè)是 dispatch_object_s * 結(jié)構(gòu)體丐黄,這個(gè)是 GCD 的基類,GCD 數(shù)據(jù)結(jié)構(gòu)都是由這個(gè)結(jié)構(gòu)體搭建起來的孔飒。

_dc: 這個(gè)是任務(wù)類型,通常 dispatch_async 內(nèi)的 block 最終都會(huì)封裝成這個(gè)數(shù)據(jù)類型艰争。

_dq: 這個(gè)是任務(wù)隊(duì)列坏瞄,我們創(chuàng)建的對(duì)列都是這個(gè)類型的,不管是串行隊(duì)列還是并發(fā)隊(duì)列甩卓。

_dqa: 這個(gè)是任務(wù)隊(duì)列的屬性鸠匀,任務(wù)隊(duì)列的屬性里面包含了任務(wù)隊(duì)列里面的一些操作函數(shù),可以表明這個(gè)任務(wù)隊(duì)列是串行還是并發(fā)隊(duì)列逾柿。

_ds: 這個(gè)是 GCD 的 sourece 缀棍,可以監(jiān)測(cè)內(nèi)核事件,文件讀寫事件和 socket 通信事件等机错。

_dsa: sourece 的屬性爬范。

_dsema: 信號(hào)量,如果了解過 pthread 都知道弱匪,信號(hào)量可以用來調(diào)度線程青瀑。

dispatch_object_t 是一個(gè)聯(lián)合體,所以當(dāng)用 dispatch_object_t 可以代表這個(gè)結(jié)合體內(nèi)的所有數(shù)據(jù)類型。

接下來詳細(xì)說明一下 dispatch_object_s 內(nèi)的結(jié)構(gòu)是怎么樣的(大家也可以閱讀這篇文章:變態(tài)的libDispatch結(jié)構(gòu)分析-object結(jié)構(gòu) - 愛悠閑):



從上兩圖可以清晰的了解到 dispatch_object_s 的結(jié)構(gòu)斥难,這里講解一下枝嘶,這個(gè)結(jié)構(gòu)體內(nèi)的一些數(shù)據(jù)的作用:

dispatch_object_s 最前面有一個(gè) vtable 的結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體內(nèi)包含了這個(gè) dispatch_object_s 的操作函數(shù)哑诊,vtable內(nèi)的數(shù)據(jù)結(jié)構(gòu)的解析:

do_type:這個(gè) dispatch_object_s 的類型群扶。

do_kined:說明這個(gè) dispatch_object_s 。

do_debug:debug 方法镀裤。

do_invoke: 喚醒隊(duì)列的方法竞阐。

do_dispose:銷毀隊(duì)列的方法,通常內(nèi)部會(huì)調(diào)用 這個(gè)對(duì)象的 finalizer 函數(shù)淹禾。

do_probe:這個(gè)方法很重要馁菜,用戶創(chuàng)建的隊(duì)列這個(gè)方法是空的,但 rootqueue 內(nèi)的這個(gè)有一個(gè) _dispatch_queue_wakeup_global 函數(shù)铃岔,這是個(gè)很重要的函數(shù)汪疮。

上面大體是 vtable 內(nèi)的數(shù)據(jù),其余的是:

do_next:鏈表的 next 毁习。

do_ref_cnt:引用計(jì)數(shù)智嚷。

do_ref_xcnt:外部引用計(jì)數(shù)。(這兩個(gè)是用來內(nèi)存管理的纺且,這里探究 GCD 的機(jī)制盏道,我也就沒多搞清楚這兩個(gè)是怎么用的)

do_suspend_cnt:suspend計(jì)數(shù),用作暫停標(biāo)志载碌,比如延時(shí)處理的任務(wù)猜嘱,設(shè)置該引用計(jì)數(shù)之后;在任務(wù)到時(shí)后嫁艇,計(jì)時(shí)器處理將會(huì)將該標(biāo)志位修改朗伶,然后喚醒隊(duì)列調(diào)度。

dispatch_queue_s:目標(biāo)隊(duì)列步咪,就是當(dāng)前這個(gè)struct x在哪個(gè)隊(duì)列運(yùn)行论皆。

do_ctext:上下文,我們要傳遞的參數(shù)猾漫。

下面說一下宾娜,了解 GCD 所需要的知識(shí):

在程序運(yùn)行的時(shí)候魄衅,GCD 會(huì)初始化 六個(gè) rootqueue 和 一個(gè) mainqueue俯在,這六個(gè) rootqueue 有低中高三種優(yōu)先級(jí)杆烁,這些 rootqueue 主要是用來調(diào)度任務(wù),我們自己創(chuàng)建的隊(duì)列其實(shí)并不能調(diào)配任務(wù)禽翼,因?yàn)槲覀儎?chuàng)建的隊(duì)列的 do_probe 都是空的坠陈,我自己創(chuàng)建的隊(duì)列都是鏈接在 rootqueue 下的萨惑,利用 rootqueue 來調(diào)配任務(wù),所以我也建議不要使用 GCD 創(chuàng)建隊(duì)列仇矾,這樣會(huì)使內(nèi)部處理更加復(fù)雜庸蔼,這個(gè)以后詳細(xì)說明。 mianqueue 是要綁定在 UI 線程的贮匕,用來更新界面的姐仅,mainqueue 是一種串行隊(duì)列。 mianqueue 在用戶層彰顯的就是 dispatch_get_main_queue()刻盐,而 rootqueue 彰顯的是 dispatch_get_global_queue 掏膏。下面講解一下 dispatch_queue_s 的結(jié)構(gòu)是怎么樣的:


上圖可以看出,dispatch_queue_s 和 dispatch_object_s 差別在于 dispatch_queue_s 多了DISPATCH_QUEUE_HEADER 和 dq_label[DISPATCH_QUEUE_MIN_LABEL_SIZE]敦锌,我們從中也可以看出馒疹,我們隊(duì)列起名要少于64個(gè)字符,DISPATCH_QUEUE_HEADER 內(nèi)的內(nèi)容有:

dq_running: 隊(duì)列正在運(yùn)行的任務(wù)數(shù)乙墙。

dq_width: 隊(duì)列的寬度(串行隊(duì)列為1颖变,并發(fā)隊(duì)列應(yīng)該大于1)。

dq_item_tail: 指向這個(gè)隊(duì)列的尾節(jié)點(diǎn)听想。

dq_item_head: 指向這個(gè)隊(duì)列的頭節(jié)點(diǎn)腥刹。

dq_serialnum: 不知道干什么的。汉买。衔峰。。

dq_finalizer_ctxt: 結(jié)束函數(shù)的的上下文(參數(shù))蛙粘。

dq_finalizer_func: 結(jié)束函數(shù)垫卤。

可以看一下一開始初始化的6個(gè) rootqueue 和 mainqueue 的內(nèi)容:



上圖展示 6個(gè) rootqueue 和 mianqueue 的具體內(nèi)容,主要講一下里面重要的出牧,在 rootqueue 里面 重要的是 do_vtable 內(nèi)的do_provbe 的函數(shù)是什么穴肘,截圖一下:


可以看出 rootsueu 的函數(shù)是 _dispatch_queue_wakeup_global,這個(gè)很重要崔列。

在 libdispatch 里面有一些原子操作函數(shù),這些函數(shù)都是由匯編寫成的旺遮,效率很高赵讯,而且不會(huì)被其他線程干擾,這里說明一下一些原子函數(shù)的作用:

dispatch_atomic_cmpxchg(A, B, C) : 將 A 和 B對(duì)比耿眉,相等边翼,則將 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 內(nèi)有一宏定義: _dispatch_hardware_pause(),這個(gè)宏定義其實(shí)是 asm("pause")棺弊,在?__asm__("pause")用法_Linux_IThao123 - IT行業(yè)第一站?說明了這個(gè)用法的好處晶密,簡(jiǎn)單說一下,在 x86 架構(gòu)的 CPU 中模她,在循環(huán)用這個(gè)匯編指令稻艰,可以保證循環(huán)不會(huì)被退出且可降低功耗,蘋果手機(jī)用的是 ARM 指令侈净,用這個(gè)匯編指令應(yīng)該作用不大尊勿。

下面的文章將詳細(xì)分析 GCD 異步執(zhí)行和同步執(zhí)行等的實(shí)現(xiàn)機(jī)制。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末用狱,一起剝皮案震驚了整個(gè)濱河市运怖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌夏伊,老刑警劉巖摇展,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異溺忧,居然都是意外死亡咏连,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門鲁森,熙熙樓的掌柜王于貴愁眉苦臉地迎上來祟滴,“玉大人,你說我怎么就攤上這事歌溉÷⒍” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵痛垛,是天一觀的道長(zhǎng)草慧。 經(jīng)常有香客問我,道長(zhǎng)匙头,這世上最難降的妖魔是什么漫谷? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮蹂析,結(jié)果婚禮上舔示,老公的妹妹穿的比我還像新娘碟婆。我一直安慰自己,他們只是感情好惕稻,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布竖共。 她就那樣靜靜地躺著,像睡著了一般缩宜。 火紅的嫁衣襯著肌膚如雪肘迎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天锻煌,我揣著相機(jī)與錄音妓布,去河邊找鬼。 笑死宋梧,一個(gè)胖子當(dāng)著我的面吹牛匣沼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捂龄,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼释涛,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了倦沧?” 一聲冷哼從身側(cè)響起唇撬,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎展融,沒想到半個(gè)月后窖认,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡告希,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年扑浸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片燕偶。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡喝噪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出指么,到底是詐尸還是另有隱情酝惧,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布伯诬,位于F島的核電站晚唇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏姑廉。R本人自食惡果不足惜缺亮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一翁涤、第九天 我趴在偏房一處隱蔽的房頂上張望桥言。 院中可真熱鬧萌踱,春花似錦、人聲如沸号阿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扔涧。三九已至园担,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間枯夜,已是汗流浹背弯汰。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留湖雹,地道東北人咏闪。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像摔吏,于是被迫代替她去往敵國(guó)和親鸽嫂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容