「少俠,GCD的基本功,練的怎麼樣了?」bash
「通過一段時間的勤學苦練,我已經爐火純青了,處理問題又快又穩,小師妹都對我另眼相看了呢」async
「真是可喜可賀,預祝少俠早日贏得伊人芳心。今天老夫來再來祝你一臂之力,少走彎路,避開魔道。」spa
「魔道? 沒遇到啊」線程
「少俠請看」code
NSLog(@"畫方");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"畫圓");
});
NSLog(@"吹口哨");
複製代碼
「鵝.... 這個怎麼感受跟我平時使用的不同呢,dispatch_sync同步碰見主線程會發生什麼呢。小生愚鈍,還請大師指點」cdn
「要弄清楚這個問題,首先要搞清楚,這段代碼運行的在主隊列,串行隊列仍是並行隊列,不一樣隊列也會致使不一樣結果。」blog
在主隊列執行隊列
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"畫方");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"畫圓");
});
NSLog(@"吹口哨");
}
//輸出
畫方
複製代碼
上面的代碼輸出「畫方」,而後程序卡死在 dispatch_sync這一行。後面的任務再也執行不了。文檔
「大師,爲何會這樣呢」get
「先來複習一下,GCD的基本招式。」
dispatch_async(queue,block)
dispatch_sync(queue,block)
這兩個方法的功能是把 block中要執行的任務,放到指定的queue中。
dispatch_async(queue,block),會當即返回,不等block執行。
dispatch_sync(queue,block),會阻塞當前線程,等待block執行完成。
複製代碼
代碼在viewDidLoad中執行,即在主線程中執行。畫方能夠順利執行,以後執行到dispatch_sync,這個代碼在主線程中執行,把block任務也放到主線程執行。主線程是串行隊列,前面一個任務執行完成以後,才能執行後面的任務,在這裏,dispatch_sync在前面,而被加入到主線程的block在後面,因此正常流程是dispatch_sync,而後執行block,但dispatch_sync必須等待block執行完成後,纔會執行完成,而根據串行隊列FIFO的規則,block必須等待dispatch_sync執行完成以後本身才能執行。這裏就形成了死鎖。代碼卡死在dispatch_sync這一行。
在並行隊列執行
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSLog(@"畫方");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"畫圓");
});
NSLog(@"吹口哨");
});
//輸出
畫方
畫圓
吹口哨
複製代碼
在並行隊列中時,畫方先執行,dispatch_sync會等待block中的任務畫圓在主隊列中完成以後,繼續執行吹口哨,由於這三個任務都在並行隊列中,因此不會存在死鎖,程序正常執行。
「原來如此,多謝大師指點,讓我沒有誤入魔道。」
dispatch_sync 文檔中以下解釋:
Calls to dispatch_sync() targeting the current queue will
result in dead-lock
假設當前代碼在queueA中執行,當用 dispatch_sync把block放到當前隊列queueA中時,就會產生死鎖。
下面這種狀況也會產生死鎖。
dispatch_queue_t queue = dispatch_queue_create("com.test.gcd", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"畫方");
dispatch_sync(queue, ^{
NSLog(@"畫圓");
});
NSLog(@"吹口哨");
});
//輸出
畫方
程序卡死在dispatch_sync這一行。
複製代碼
「知道了箇中原理,遇到問題就能輕鬆化解了。將來的修煉之路已經給你指名,快快修煉去罷。」