iOS 死锁案例和产生的原因
iOS 死锁案例和产生的原因
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_sync(dispatch_get_main_queue(), ^{
[self test];
});
}
- (void)test{
}
上面的代码会打印什么呢?答案是死锁
死锁的原因是由于队列引起的循环等待:
我们在主队列提交了 viewdidload 任务,之后又提交了一个block任务,我们在主线程中先去处理viewdidload任务,我们的viewdidload任务,里面需要等block任务同步执行完毕,才可以向下走,所以viewdidload依赖于后面提交的block任务,而我们block是在主队列中执行的,要依赖于队列的先进先出的性质,block就要等待viewdidload执行完毕才可以,因为他也是在主队列上面执行的,是先被加到主队列里面的,这样就产生了相互等待,产生了死锁。
- (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方法,在主线程中执行,这时候我们又提交了一个block在另一个串行队列中执行,这个任务是个同步的,所以意味着在当前线程执行,也就是在 主线程中执行,当这个任务在主线程中执行完成后,就继续执行主队列中的任务,所以就没有问题,因为是两个队列,不存在相互等待的问题,问题由于产生了一个串行队列,如果viewdidload方法不再主队列中执行,代码类似于这样
- (void)viewDidLoad {
[super viewDidLoad];
_queue = dispatch_queue_create("com.rongcloud.sunchengxiu", NULL);
dispatch_sync(_queue, ^{
[self test];
});
}
- (void)test{
dispatch_sync(_queue, ^{
NSLog(@"123");
});
}
那么依然会产生死锁,因为两个同步任务都分配到一个同步队列当中,都需要互相等待对方完成,所以就形成了死锁。
下面的代码是否会产生死锁?打印什么?
_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打印完毕之后打印,因为当前队列是并发队列,所以提交的任务可以并发执行,虽然之前提交的那个任务没有执行完毕,但是不影响,因为是并发队列,所以可以正常执行下一个block。
练习题
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");
});
上面的代码不会死锁,因为并发队列可以同时执行,不需要向串行队列那样先进先出排队执行
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");
});
上面的代码不会死锁 ,因为他们在不同的队列,互不干扰
总结
使用 sync 函数,往当前串行队列添加就会产生死锁。
比如上面的代码,我们把 queue 换成 DISPATCH_QUEUE_CONCURRENT,不会产生死锁,因为是并发的,把下面的queue换成另一个,也不会,因为不在一个队列里面啊,把sync 换成async也不会,因为不需要卡主当前线程,也不需要等待,所以也不会产生死锁。