iOS 死鎖案例和產(chǎn)生的原因
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_sync(dispatch_get_main_queue(), ^{
[self test];
});
}
- (void)test{
}
上面的代碼會打印什么呢?答案是死鎖
死鎖的原因是由于隊列引起的循環(huán)等待:
我們在主隊列提交了 viewdidload 任務(wù)峭梳,之后又提交了一個block任務(wù)酪捡,我們在主線程中先去處理viewdidload任務(wù)耕肩,我們的viewdidload任務(wù)典奉,里面需要等block任務(wù)同步執(zhí)行完畢悼沿,才可以向下走屿笼,所以viewdidload依賴于后面提交的block任務(wù)牺荠,而我們block是在主隊列中執(zhí)行的,要依賴于隊列的先進(jìn)先出的性質(zhì)刁卜,block就要等待viewdidload執(zhí)行完畢才可以志电,因為他也是在主隊列上面執(zhí)行的,是先被加到主隊列里面的蛔趴,這樣就產(chǎn)生了相互等待挑辆,產(chǎn)生了死鎖。
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_queue_create("com.rongcloud.sunchengxiu", NULL);
dispatch_sync(queue, ^{
[self test];
});
}
- (void)test{
NSLog(@"123");
}
那么下面的代碼又是打印什么呢孝情?答案是可以正常打印
我們在主隊列中提交了一個viewdidload方法鱼蝉,在主線程中執(zhí)行,這時候我們又提交了一個block在另一個串行隊列中執(zhí)行箫荡,這個任務(wù)是個同步的魁亦,所以意味著在當(dāng)前線程執(zhí)行,也就是在 主線程中執(zhí)行羔挡,當(dāng)這個任務(wù)在主線程中執(zhí)行完成后洁奈,就繼續(xù)執(zhí)行主隊列中的任務(wù),所以就沒有問題,因為是兩個隊列绞灼,不存在相互等待的問題利术,問題由于產(chǎn)生了一個串行隊列,如果viewdidload方法不再主隊列中執(zhí)行低矮,代碼類似于這樣
- (void)viewDidLoad {
[super viewDidLoad];
_queue = dispatch_queue_create("com.rongcloud.sunchengxiu", NULL);
dispatch_sync(_queue, ^{
[self test];
});
}
- (void)test{
dispatch_sync(_queue, ^{
NSLog(@"123");
});
}
那么依然會產(chǎn)生死鎖,因為兩個同步任務(wù)都分配到一個同步隊列當(dāng)中印叁,都需要互相等待對方完成,所以就形成了死鎖军掂。
下面的代碼是否會產(chǎn)生死鎖?打印什么轮蜕?
_queue = dispatch_queue_create("com.rongcloud.sunchengxiu", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(_queue, ^{
NSLog(@"1");
dispatch_sync(_queue, ^{
sleep(3);
NSLog(@"2");
});
NSLog(@"3");
});
答案是按照123打印屁商,3會等待3秒2打印完畢之后打印船侧,因為當(dāng)前隊列是并發(fā)隊列,所以提交的任務(wù)可以并發(fā)執(zhí)行蜜宪,雖然之前提交的那個任務(wù)沒有執(zhí)行完畢终议,但是不影響税课,因為是并發(fā)隊列闲延,所以可以正常執(zhí)行下一個block。
練習(xí)題
dispatch_queue_t queue = dispatch_queue_create("aasdf", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"1");
dispatch_sync(queue, ^{
NSLog(@"2");
});
NSLog(@"3");
});
上面的代碼會死鎖
dispatch_queue_t queue = dispatch_queue_create("aasdf", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"1");
dispatch_sync(queue, ^{
NSLog(@"2");
});
NSLog(@"3");
});
上面的代碼不會死鎖韩玩,因為并發(fā)隊列可以同時執(zhí)行,不需要向串行隊列那樣先進(jìn)先出排隊執(zhí)行
dispatch_queue_t queue = dispatch_queue_create("aasdf", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue1 = dispatch_queue_create("aasdf", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"1");
dispatch_sync(queue1, ^{
NSLog(@"2");
});
NSLog(@"3");
});
上面的代碼不會死鎖 陆馁,因為他們在不同的隊列找颓,互不干擾
總結(jié)
使用 sync 函數(shù),往當(dāng)前串行隊列添加就會產(chǎn)生死鎖叮贩。
比如上面的代碼击狮,我們把 queue 換成 DISPATCH_QUEUE_CONCURRENT,不會產(chǎn)生死鎖,因為是并發(fā)的益老,把下面的queue換成另一個彪蓬,也不會,因為不在一個隊列里面啊捺萌,把sync 換成async也不會档冬,因為不需要卡主當(dāng)前線程,也不需要等待桃纯,所以也不會產(chǎn)生死鎖酷誓。