平時總在用GCD,但你知不知道,GCD一不小心就會出現(xiàn)死鎖,如果死鎖在主線程上,整個程序就完了,所以避免死鎖是我們則無旁貸的責任忍些。
那我們先看看造成GCD死鎖的三要素(以下內(nèi)容是我個人總結(jié),并寫了一些測試用例,如有不對的地方,請大家指正 PS:我把GCD死鎖分成 “普通死鎖” ,“高級死鎖”,"混合死鎖")
普通死鎖 必要條件
1.隊列 串行隊列:1 并行隊列:0
2.調(diào)度方法 同步調(diào)用(dispatch_sync):1 異步調(diào)用(dispatch_async):0
3.同一個Q 當前所分發(fā)到的Q 和 "外部Q" 是否是同一個Q 同一個:1 不同:0
PS:"外部Q"是指
1.當前嵌套在外部的Q 如以下形式,Q1就是外部Q
dispatch_sync(Q1, ^{
NSLog(@"b");
dispatch_sync(Q2, ^{
NSLog(@"c");
});
});)
2.外部的方法執(zhí)行時 所在的Q 如以下形式 dead1第二次運行時所在的Q是Q1 它就是外部Q
- (void)dead1{
NSLog(@"不死1");
__weak typeof (self) weakSelf = self;
dispatch_sync(Q1, ^{
NSLog(@"第二次運行死");
[weakSelf dead1];
});}
#######結(jié)論: 如果三個條件同時滿足 則死鎖,如果其中一個不滿足 不會死鎖
高級死鎖 必要條件
1.調(diào)度方法 同步阻塞調(diào)用(dispatch_barrier_sync):1 異步阻塞調(diào)用(dispatch_barrier_async):0
2.同一個Q 當前所分發(fā)到的Q 和 "外部Q" 是否是同一個Q 同一個:1 不同:0
#######結(jié)論: 如果兩個條件同時滿足 則死鎖,如果其中一個不滿足 不會死鎖 (高級死鎖主要針對dispatch_barrier而言)
混合死鎖 必要條件
1.調(diào)度方法 同步阻塞調(diào)用(dispatch_barrier_sync)或同步調(diào)用(dispatch_sync):1 異步阻塞調(diào)用(dispatch_barrier_async)或異步調(diào)用(dispatch_async):0
2.同一個Q 當前所分發(fā)到的Q 和 "外部Q" 是否是同一個Q 同一個:1 不同:0
#######結(jié)論: 如果兩個條件同時滿足 則死鎖,如果其中一個不滿足 不會死鎖 (混合死鎖主要針對dispatch_barrier 和 dispatch_async,dispatch_sync嵌套調(diào)用而言)
以下是死鎖測試用例
- (void)viewDidLoad
{
[super viewDidLoad];
// 創(chuàng)建兩個串行隊列和一個并行隊列
_serialQueue = dispatch_queue_create("aabbcc", DISPATCH_QUEUE_SERIAL);
_secondSerialQueue = dispatch_queue_create("ssss", DISPATCH_QUEUE_SERIAL);
_concurrentQueue = dispatch_queue_create("dddd", DISPATCH_QUEUE_CONCURRENT);
[self dead1];
[self dead2];
[self dead3];
}
一 普通死鎖
- (void)dead1
{
NSLog(@"不死1");
__weak typeof (self) weakSelf = self;
dispatch_sync(_serialQueue, ^{
NSLog(@"第二次運行死");
[weakSelf dead1];
});
}
PS:打印日志如下:
2015-10-29 16:46:35.611 DeadLockTest[19971:204243] 不死1
2015-10-29 16:46:35.612 DeadLockTest[19971:204243] 第二次運行死
2015-10-29 16:46:35.612 DeadLockTest[19971:204243] 不死1
原因 在[weakSelf dead1]; 循環(huán)調(diào)用方法本身時,它就在_serialQueue隊列上運行,此時“dispatch_sync(_serialQueue, ^{}” 滿足條件三,同一個Q _serialQueue上 同時又滿足 串行Q 和 同步分發(fā) 所以在第二次運行時產(chǎn)生死鎖。
- (void)dead2
{
NSLog(@"不死1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"死鎖");
});
}
PS:打印日志如下:
2015-10-29 16:52:45.435 DeadLockTest[20036:206574] 不死1
原因 dispatch_get_main_queue() 是主Q dead2本身就在主Q 上運行 符合同一個Q 并且同時符合2,3條件 所以死鎖
二 高級死鎖
//死在子線程
- (void)dead3
{
//并行隊列死鎖
NSLog(@"a");
dispatch_async(_concurrentQueue, ^{
NSLog(@"b");
dispatch_barrier_sync(_concurrentQueue, ^{
NSLog(@"c");
});
});
}
PS:打印日志如下:
2015-10-29 18:15:02.522 DeadLockTest[27790:256689] a
2015-10-29 18:15:05.919 DeadLockTest[27790:256851] b
原因 同時滿足 1都是同一個Q _concurrentQueue 2同步分發(fā) 使用dispatch_barrier_sync 所以死鎖
三 混合死鎖
//混合模式,內(nèi)部使用dispatch_sync 又是同一Q _concurrentQueue 死鎖
- (void)dead4
{
NSLog(@"不死1");
dispatch_barrier_async(_concurrentQueue, ^{
NSLog(@"不死2");
dispatch_sync(_concurrentQueue, ^{
NSLog(@"死在子線程上");
});
});
}
PS:打印日志如下:
2015-10-30 10:13:08.544 DeadLockTest[5346:35961] 不死1
2015-10-30 10:13:08.550 DeadLockTest[5346:36036] 不死2
原因 同時滿足 1都是同一個Q _concurrentQueue 2同步分發(fā) 使用dispatch_sync 所以死鎖
//混合模式,內(nèi)部使用dispatch_barrier_sync 又是同一Q _concurrentQueue 死鎖
- (void)dead5
{
NSLog(@"不死1");
dispatch_async(_concurrentQueue, ^{
NSLog(@"不死2");
dispatch_barrier_sync(_concurrentQueue, ^{
NSLog(@"死在子線程上");
});
});
}
PS:打印日志如下:
2015-10-30 10:14:08.544 DeadLockTest[5346:35961] 不死1
2015-10-30 10:14:08.550 DeadLockTest[5346:36036] 不死2
原因 同時滿足 1都是同一個Q _concurrentQueue 2同步分發(fā) 使用dispatch_barrier_sync 所以死鎖
以下是非死鎖測試用例
/*打破條件1 _concurrentQueue 是并行隊列 不死鎖 */
- (void)noDead1
{
NSLog(@"a");
dispatch_async(_concurrentQueue, ^{
NSLog(@"b");
dispatch_sync(_concurrentQueue, ^{
NSLog(@"c");
});
});
}
PS:打印日志如下
2015-10-29 18:22:36.724 DeadLockTest[27922:261502] a
2015-10-29 18:22:36.725 DeadLockTest[27922:261633] b
2015-10-29 18:22:36.726 DeadLockTest[27922:261633] c
/*雖然說三條日志都在主線程上執(zhí)行,但是因為是在兩個不同的隊列上 打破條件3
不會死鎖 _serialQueue和_secondSerialQueue 不是同一個隊列*/
- (void)noDead2
{
NSLog(@"不死1");
dispatch_sync(_serialQueue, ^{
NSLog(@"不死2");
dispatch_sync(_secondSerialQueue, ^{
NSLog(@"不死3");
});
});
}
PS:打印日志如下
2015-10-29 18:26:23.876 DeadLockTest[27977:263046] 不死1
2015-10-29 18:26:23.877 DeadLockTest[27977:263046] 不死2
2015-10-29 18:26:23.878 DeadLockTest[27977:263046] 不死3
以上就是對死鎖的分析,如果掌握了這幾個必要條件,趕快用下面的鏈接練練手吧,檢驗一下對不對
http://www.cnblogs.com/tangbinblog/p/4133481.html