1、什麼是GCD?編程
如下是摘自蘋果的官方說明。安全
Grand Central Dispatch(GCD)是異步執行任務的技術之一。通常將應用程序中記述的線程管理用的代碼在系統級中實現。開發者只須要定義想執行的任務並追加到適當的Dispatch Queue中,GCD就能生成必要的線程並計劃執行任務。多線程
2、GCD實現之Dispatch Queue併發
GCD的API所有包含在libdispatch庫中的C語言函數。Dispatch Queue經過結構體和鏈表,被實現爲FIFO隊列。FIFO隊列管理是經過dispatch_async等函數所追加的Block。異步
Block並非直接加入FIFO隊列,而是先加入Dispatch Continuation這一dispatch_continution_t類結構體中,而後再加入FIFO隊列。該Dispatch Continuation用於記憶Block所屬的Dispatch Group和其餘一些信息,至關於通常常說的執行上下文。async
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種。spa
優先級中附有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。
以上爲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執行的大概過程。
3、線程和隊列
線程是代碼執行的路徑,隊列則是用於保存以及管理任務的,線程負責去隊列中取任務進行執行。
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();
二、同步和異步
dispatch_async (異步操做函數),就是將指定的Block「非同步」地追加到指定的隊列(queue)中。dispatch_async函數不作任何等待。會新開線程
dispatch_sync( 同步操做函數),就是將指定的Block「同步」地追加到指定的隊列(queue)中。在追加Block結束以前,dispatch_sync函數會一直等待;不會新開線程
三、隊列和操做的組合
串行隊列同步操做:同步操做不會新開線程、操做順序執行
串行隊列異步操做:異步操做新開一個子線程、操做順序執行,「最安全的選擇」
並行隊列同步操做:同步操做不會新開線程、操做順序執行
並行隊列異步操做:異步操做會新開多個線程(有多少任務,就開n個線程執行)、操做無序執行;隊列前若是有其餘任務,會等待前面的任務完成以後再執行;場景:既不影響主線程,又不須要順序執行的操做!
全局隊列異步操做:異步操做會新建多個線程、操做無序執行,隊列前若是有其餘任務,會等待前面的任務完成以後再執行
全局隊列同步操做:同步操做不會新建線程、操做順序執行
主隊列異步操做:異步操做都在主線程上順序執行的,不存在異步的概念
主隊列同步操做:會死鎖
四、會引發死鎖的2種狀況
一、在主線程中運用主隊列同步。
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"hello");
});
}
同步對於任務是馬上執行的,那麼當把任務放進主隊列時,它就會立馬執行,只有執行完這個任務,viewDidLoad纔會繼續向下執行。
而viewDidLoad和任務都是在主隊列上的,因爲隊列的先進先出原則,任務又需等待viewDidLoad執行完畢後才能繼續執行,viewDidLoad和這個任務就造成了相互循環等待,就形成了死鎖。
想避免這種死鎖,能夠將同步改爲異步dispatch_async,或者將dispatch_get_main_queue換成其餘串行或並行隊列,均可以解決。
二、在串行隊列中同步的向這個串行隊列追加Block
dispatch_queue_t serialQueue = dispatch_queue_create("xxx", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
dispatch_sync(serialQueue, ^{
NSLog(@"hello");
});
});
想避免這種死鎖,能夠將同步改爲異步dispatch_async,或者將串行隊列換爲並行隊列,均可以解決。
以上部份內容參考自《Objective-C高級編程》一書