一、什麼是GCD?
以下是摘自蘋果的官方說明。
Grand Central Dispatch(GCD)是非同步執行任務的技術之一。一般將應用程式中記述的執行緒管理用的程式碼在系統級中實現。開發者只需要定義想執行的任務並追加到適當的Dispatch Queue中,GCD就能生成必要的執行緒並計劃執行任務。
二、GCD實現之Dispatch Queue
- 用於管理追加的Block的C語言層實現的FIFO佇列
- Atomic函式中實現的用於排他控制的輕量級訊號
- 用於管理執行緒的C語言層實現的一些容器
GCD的API全部包含在libdispatch庫中的C語言函式。Dispatch Queue通過結構體和連結串列,被實現為FIFO佇列。FIFO佇列管理是通過dispatch_async等函式所追加的Block。
Block並不是直接加入FIFO佇列,而是先加入Dispatch Continuation這一dispatch_continution_t類結構體中,然後再加入FIFO佇列。該Dispatch Continuation用於記憶Block所屬的Dispatch Group和其他一些資訊,相當於一般常說的執行上下文。
Dispatch Queue可通過dispatch_set_target_queue函式設定,可以設定執行該Dispatch Queue處理的Dispatch Queue為目標。該目標可像串珠子一樣,設定多個連線在一起的Dispatch Queue。但是在連線串的最後必須設定為Main Dispatch Queue,或各種優先順序的Global Dispatch Queue,或是準備用於Serial Dispatch Queue的各種優先順序的 Global Dispatch Queue.
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)
優先順序中附有Overcommit的Global Dispatch Queue使用在Serial Dispatch Queue中。如Overcommit這個名稱所示,不管系統狀態如何,都會強制生成執行緒的Dispatch Queue。
這8種Global Dispatch Queue各使用1個pthread_workqueue。GCD初始化時,使用pthread_workqueue_create_np函式生成pthread_workqueue。
pthread_workqueue包含在Libc提供的pthreads API中。其使用bsdthread_register和workq_open系統呼叫,在初始化XNU核心的workqueue之後獲取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則始終生成執行緒。
workqueue的執行緒執行pthread_workqueue函式,該函式呼叫libdispatch的回撥函式。在該回撥函式中執行加入到Dispatch Continuation的Block。
Block執行結束後,進行通知Dispatch Group結束、釋放Dispatch Continuation等處理,開始準備執行加入到Global Dispatch Queue中的下一個Block。
以上就是Dispatch Queue執行的大概過程。
三、執行緒和佇列
執行緒是程式碼執行的路徑,佇列則是用於儲存以及管理任務的,執行緒負責去佇列中取任務進行執行。
1、佇列
是管理執行緒的,相當於執行緒池,能管理執行緒什麼時候執行。
佇列分為序列佇列和並行佇列等
序列佇列:佇列中的任務按順序執行
並行佇列:佇列中的任務會併發執行。任務執行完畢了,不一定出佇列。只有前面的任務執行完了,才會出佇列。
序列佇列:佇列中的任務只會順序執行,多個序列佇列可並行執行
dispatch_queue_t q = dispatch_queue_create(“xxx”,DISPATCH_QUEUE_SERIAL);
並行佇列:佇列中的任務會併發執行
dispatch_queue_t q = dispatch_queue_create(“xxx”, DISPATCH_QUEUE_CONCURRENT);
全域性佇列:與並行佇列類似,但除錯時,無法確認操作所在佇列
dispatch_queue_t q = dispatch_get_global_queue(dispatch_queue_priority_default, 0);
主佇列:每一個程式對應唯一一個主佇列;在多執行緒開發中,使用主佇列更新UI
dispatch_queue_t q = dispatch_get_main_queue();
2、同步和非同步
dispatch_async (非同步操作函式),就是將指定的Block“非同步”地追加到指定的佇列(queue)中。dispatch_async函式不做任何等待。會新開執行緒
dispatch_sync( 同步操作函式),就是將指定的Block“同步”地追加到指定的佇列(queue)中。在追加Block結束之前,dispatch_sync函式會一直等待;不會新開執行緒
3、佇列和操作的組合
序列佇列同步操作:同步操作不會新開執行緒、操作順序執行
序列佇列非同步操作:非同步操作新開一個子執行緒、操作順序執行,“最安全的選擇”
並行佇列同步操作:同步操作不會新開執行緒、操作順序執行
並行佇列非同步操作:非同步操作會新開多個執行緒(有多少任務,就開n個執行緒執行)、操作無序執行;佇列前如果有其他任務,會等待前面的任務完成之後再執行;場景:既不影響主執行緒,又不需要順序執行的操作!
全域性佇列非同步操作:非同步操作會新建多個執行緒、操作無序執行,佇列前如果有其他任務,會等待前面的任務完成之後再執行
全域性佇列同步操作:同步操作不會新建執行緒、操作順序執行
主佇列非同步操作:非同步操作都在主執行緒上順序執行的,不存在非同步的概念
主佇列同步操作:會死鎖
4、會引起死鎖的2種情況
1、在主執行緒中運用主佇列同步。
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"hello");
});
}
同步對於任務是立刻執行的,那麼當把任務放進主佇列時,它就會立馬執行,只有執行完這個任務,viewDidLoad才會繼續向下執行。
而viewDidLoad和任務都是在主佇列上的,由於佇列的先進先出原則,任務又需等待viewDidLoad執行完畢後才能繼續執行,viewDidLoad和這個任務就形成了相互迴圈等待,就造成了死鎖。
想避免這種死鎖,可以將同步改成非同步dispatch_async,或者將dispatch_get_main_queue換成其他序列或並行佇列,都可以解決。
2、在序列佇列中同步的向這個序列佇列追加Block
dispatch_queue_t serialQueue = dispatch_queue_create("xxx", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
dispatch_sync(serialQueue, ^{
NSLog(@"hello");
});
});
想避免這種死鎖,可以將同步改成非同步dispatch_async,或者將序列佇列換為並行佇列,都可以解決。
以上部分內容參考自《Objective-C高階程式設計》一書