OC - GCD 中死锁分析

1,295 阅读2分钟

基本知识点:

死锁:

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

队列:

  • 串行队列:任务一个一个按顺序执行,后面的任务必须等待前面的任务执行完毕后才能执行。
  • 并发队列:多个任务可以同时执行, 后面的任务不需等待前面的任务执行完毕就可以执行。

同步(sync) 和 异步(async):

  • 同步: 立即执行(需要等待),不具备开启新线程的能力
  • 异步: 不需等待。具备开启新线程的能力,但是不一定会开启。(如:队列为主队列时)

主队列

主队列是一个特殊的串行队列,主队列的任务在主线程中执行。

死锁分析

场景一

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self test1];
}

- (void)test1 {
    NSLog(@"任务1------");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
         NSLog(@"任务2------");
    });
    
    NSLog(@"任务3--------");
}

上面代码会发生死锁, 原因:queue为主队列,任务2又是同步执行。 任务2的执行必须等待 viewDidLoad 这个任务执行完, 而viewDidLoad这个任务执行完的前提是任务2执行完,两者相互等待,造成死锁。解决方案:(1)将同步改为异步 (2)将任务2加入到其他队列中

场景二

- (void)test2 {
    NSLog(@"任务1------");
    
    // 创建一个串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.longchi", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{  // 异步任务
        NSLog(@"任务2------");
        dispatch_sync(queue, ^{
            NSLog(@"任务3------");
        });
        NSLog(@"任务4--------");
    });
    
    NSLog(@"任务5--------");
}

上面代码也会发生死锁, 原因:queue为串行队列,任务3的执行必须等待异步任务的执行完毕,而异步任务要执行完毕就必须等待任务3先执行完。两者相互等待,造成死锁。 解决方案:(1) queue改为并发队列 (2) 将任务3加入其他队列 (3) 任务3也异步执行。

总结

使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(会发生死锁)。