GCD內部實現

Dispatch Queue編程

  Dispatch Queue 對於咱們開發者來講應該是很是熟悉了,運用的場景很是之多,可是他的內部是如何實現的呢?多線程

  • 用於管理追加的Block的C語言層實現的FIFO隊列
  • Atomic函數中實現的用於排他控制的輕量級信號
  • 用於管理線程的C語言層實現的一些容器

  不難想象,GCD的實現須要使用以上這些工具,可是若是僅用這些內容即可實現,那麼就不須要內核級實現了。(實際上在通常的Linux內核中可能使用面向Linux操做系統而移植的GCD)。併發

  甚至有人會想,只要努力編寫線程管理的代碼,就根本用不到GCD,是這樣的嗎?框架

  咱們先來回顧一下蘋果的官方說明:async

 

  一般,應用程序中編寫的線程管理用的代碼要在系統級實現。函數

  實際上正如這句話所說,在系統級即iOS和OS X的核心XNU內核級上實現,所以不管編程人員如何努力編寫管理線程的代碼,在性能方面也不可能賽過XNU內核級所實現的GCD。工具

  使用GCD要比使用pthreads和NSThread這些通常的多線程編程API更好。而且,若是用GCD就沒必要編寫爲操做線程反覆出現的相似的源代碼(這裏被稱爲固定源代碼片斷),而能夠在線程中集中實現處理內容,真的是好處多多。咱們儘可能多使用GCD或者使用了Cocoa框架GCD的NSOperationQueue類等API。oop

  那麼首先確認一下用於實現Dispatch Queue 而使用的軟件組件。如表所示:性能

 

 

  編程人員所使用GCD的API所有包含在libdispatch庫的C語言函數。Dispatch Queue經過結構體和鏈表,被實現爲FIFO隊列。FIFO隊列主要是負責管理經過dispatch_async等函數所追加的一系列Blocks。因此咱們能夠理解爲一旦咱們在程序中由上到下追加了一組Blocks,那麼排除掉dispatch_after,其內部的追加過程是一個先進先出原則。spa

  可是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的性能是不可能的。

 

原文連接:http://blog.csdn.net/mobanchengshuang/article/details/10839049

相關文章
相關標籤/搜索