造成死鎖的情況分析
第一種是:主隊(duì)列同步任務(wù)很容易造成死鎖,因?yàn)橹麝?duì)列是在主線程空閑時(shí)才會(huì)調(diào)度隊(duì)列中的任務(wù)在主線程上執(zhí)行.如果主線程不是空閑狀態(tài),那么主隊(duì)列中不論是同步任務(wù)還是異步任務(wù)都會(huì)死鎖,永遠(yuǎn)不會(huì)執(zhí)行.
- (void)gcdDemo1
NSLog(@"begin %@", [NSThreadcurrentThread]);
// 主隊(duì)列同步執(zhí)行任務(wù)
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"%@", [NSThreadcurrentThread]);
});
NSLog(@"end %@", [NSThreadcurrentThread]);
}
- (void)gcdDemo2 {
// 1. 串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("cn.zh.queue", DISPATCH_QUEUE_SERIAL);
NSLog(@"begin %@", [NSThreadcurrentThread]);
// 主隊(duì)列同步執(zhí)行任務(wù)通過外層嵌套子線程保證當(dāng)前函數(shù)中任務(wù)不需要等待主隊(duì)列任務(wù)執(zhí)行完.
dispatch_async(queue, ^{
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"1%@", [NSThreadcurrentThread]);
});
});
// 由于主隊(duì)列中放置了同步任務(wù),通過上一步操作,表明主線程的任務(wù)必須要執(zhí)行完才能執(zhí)行下面的同步任務(wù)(也是主線程),但是下面的同步任務(wù)因?yàn)樯厦娴闹麝?duì)列同步任務(wù)需要等待主線程空閑才能執(zhí)行,相互等待,造成死鎖.
dispatch_sync(queue, ^{
NSLog(@"2%@", [NSThreadcurrentThread]);
});
NSLog(@"end %@", [NSThreadcurrentThread]);
}
注意:如果上面的:
dispatch_sync(queue, ^{
NSLog(@"2%@", [NSThreadcurrentThread]);
});
改成:
dispatch_async(queue, ^{
NSLog(@"2%@", [NSThreadcurrentThread]);
});
執(zhí)行結(jié)果肯定永遠(yuǎn)是這個(gè)順序:
begin <NSThread: 0x7f89da4080d0>{number = 1, name = main}
end <NSThread: 0x7f89da4080d0>{number = 1, name = main}
1<NSThread: 0x7f89da4080d0>{number = 1, name = main}
2<NSThread: 0x7f89da710f20>{number = 2, name = (null)}
因?yàn)?上面的主隊(duì)列調(diào)度主線程的是同步任務(wù),需要立即執(zhí)行完才能執(zhí)行下面的操作,但是主線程目前還沒有空閑,需要執(zhí)行完本身gcdDemo2的NSLog(@"end %@", [NSThreadcurrentThread])才算完,所以begin —> end —>1 —>2
第二種是:
- 串行隊(duì)列同步任務(wù)—>嵌套同步任務(wù)—>導(dǎo)致當(dāng)前線程死鎖.因?yàn)镃PU執(zhí)行到3的位置時(shí),因?yàn)槭峭饺蝿?wù),需要等待當(dāng)前線程(目前是主線程)執(zhí)行完,也即是2位置的外層嵌套的同步任務(wù).由于外層嵌套的同步任務(wù)又要等待3位置的同步任務(wù)執(zhí)行完,所以導(dǎo)致相互等待,死鎖.
- (void)gcdDemo4 {
// 1. 串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("cn.zh.queue", DISPATCH_QUEUE_SERIAL);
// 2. 串行隊(duì)列異步
dispatch_sync(queue, ^{
NSLog(@"begin %@", [NSThread currentThread]);
// 3. 同步任務(wù)中嵌套同步任務(wù)會(huì)導(dǎo)致當(dāng)前主線程死鎖
dispatch_sync(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
NSLog(@"end %@", [NSThread currentThread]);
});
}
- 串行隊(duì)列異步任務(wù)—>嵌套同步任務(wù)—>導(dǎo)致當(dāng)前線程死鎖.因?yàn)镃PU執(zhí)行到3的位置時(shí),因?yàn)槭峭饺蝿?wù),需要等待當(dāng)前線程(目前是子線程)執(zhí)行完,也即是2位置的外層嵌套的子線程的異步任務(wù).由于外層嵌套的子線程異步任務(wù)執(zhí)行時(shí)又要等待3位置的同步任務(wù)執(zhí)行完,所以導(dǎo)致相互等待,死鎖.
- (void)gcdDemo4 {
// 1. 串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("cn.zh.queue", DISPATCH_QUEUE_SERIAL);
// 2. 串行隊(duì)列異步
dispatch_async(queue, ^{
NSLog(@"begin %@", [NSThread currentThread]);
// 3. 異步任務(wù)中嵌套同步任務(wù)會(huì)導(dǎo)致當(dāng)前子線程死鎖
dispatch_sync(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
NSLog(@"end %@", [NSThread currentThread]);
});
}
注意:如果換成并行隊(duì)列就不會(huì)死鎖,因?yàn)椴⑿嘘?duì)列異步任務(wù)時(shí),分配了不同的子線程,不會(huì)在一條子線程上死鎖.
總結(jié):導(dǎo)致線程死鎖情況只需要考慮兩點(diǎn):1)是不是同一個(gè)線程上.2)是不是相互等待
容易導(dǎo)致死鎖的情況:
1)主隊(duì)列同步任務(wù),如果主線程上的執(zhí)行函數(shù)沒有用子線程去”包”一下,就會(huì)因?yàn)橹骶€程上的執(zhí)行函數(shù)BLOCK大任務(wù)與主隊(duì)列中需要調(diào)度到主線程的BLOCK任務(wù)相互等待,導(dǎo)致死鎖;
注意:主隊(duì)列只有在主線程空閑狀態(tài)才會(huì)將任務(wù)調(diào)度到主線程執(zhí)行,所以主隊(duì)列的異步任務(wù),也可能出現(xiàn)永遠(yuǎn)無法執(zhí)行的情況.
2)串行隊(duì)列同步任務(wù)嵌套同步任務(wù),如上演示的demo,會(huì)導(dǎo)致當(dāng)前線程死鎖;
串行隊(duì)列異步任務(wù)嵌套同步任務(wù),如上演示的demo,會(huì)導(dǎo)致當(dāng)前子線程死鎖;