iOS 死锁案例和产生的原因

2019-12-16  本文已影响0人  孙掌门

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也不会,因为不需要卡主当前线程,也不需要等待,所以也不会产生死锁。

上一篇下一篇

猜你喜欢

热点阅读