GCD 之執行緒死鎖
阿新 • • 發佈:2019-02-09
GCD 確實好用 ,很強大,相比NSOpretion 無法提供 取消任務的功能。
如此強大的工具用不好可能會出現執行緒死鎖。 如下程式碼:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"=================4");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"=================5");
});
NSLog(@"=================6");
}
GCD Queue 分為三種:
1,The main queue :主佇列,主執行緒就是在個佇列中。
2,Global queues : 全域性併發佇列。
3,使用者佇列:是用函式 dispatch_queue_create
建立的自定義佇列
dispatch_sync 和 dispatch_async 區別:
dispatch_async(queue,block) async 非同步佇列,dispatch_async
函式會立即返回, block會在後臺非同步執行。
dispatch_sync(queue,block) sync 同步佇列,dispatch_sync
函式不會立即返回,及阻塞當前執行緒,等待
block同步執行完成。
分析上面程式碼:
viewDidLoad 在主執行緒中, 及在
dispatch_get_main_queue() 中,執行到sync 時 向
dispatch_get_main_queue()插入 同步 threed1.
sync 會等到 後面block 執行完成才返回, sync 又再 dispatch_get_main_queue() 佇列中,
它是序列佇列,sync 是後加入的,前一個是主執行緒,
所以 sync 想執行 block 必須等待主執行緒執行完成,主執行緒等待 sync 返回,去執行後續內容。
造成死鎖,sync 等待mainThread 執行完成, mianThread 等待sync 函式返回。
下面例子:
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"=================1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"=================2");
});
NSLog(@"=================3");
});
}
程式會完成執行,為什麼不會出現死鎖。
首先: async 在主執行緒中 建立了一個非同步執行緒 加入 全域性併發佇列,async 不會等待block 執行完成,立即返回,
1,async 立即返回, viewDidLoad 執行完畢,及主執行緒執行完畢。
2,同時,全域性併發佇列立即執行非同步 block , 列印 1, 當執行到 sync 它會等待 block 執行完成才返回, 及等待
dispatch_get_main_queue() 佇列中的 mianThread 執行完成, 然後才開始呼叫block 。
因為1 和 2 幾乎同時執行,因為2 在全域性併發佇列上, 2 中執行到sync 時 1 可能已經執行完成或 等了一會,mainThread 很快退出, 2 等已執行後續內容。
如果阻塞了主執行緒,2 中的sync 就無法執行啦,mainThread 永遠不會退出, sync 就永遠等待著,
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"=================1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"=================2");
});
NSLog(@"=================3");
});
NSLog(@"==========阻塞主執行緒");
while (1) {
}
NSLog(@"========2==阻塞主執行緒");
}
列印如下:
2014-11-30 17:56:22.296 Test[6108:379350] =================1
2014-11-30 17:56:22.296 Test[6108:379231] ==========阻塞主執行緒
永遠等著。。。。。
知道原理以後就會減少出錯啦。