美文网首页
iOS GCD死锁的情况和解决办法

iOS GCD死锁的情况和解决办法

作者: 天空知诚 | 来源:发表于2020-04-17 11:32 被阅读0次

1、同步串行主队列

dispatch_sync(dispatch_get_main_queue(), ^(void){
        NSLog(@"这里死锁了");
});

因为dispatch_sync是一个同步队列,所以会堵塞在这里,直至这个dispatch_sync有返回才会继续执行下去,此时这个block是加入到主队列里面,并且后面的代码在block之前加入到主队列,然而主队列是一个FIFO的串行队列,所以block需要后面的代码先执行,但是由于这个dispatch_sync阻塞了,所以后面的代码又没法执行,所以导致相互阻塞了。

解决方案

  • 切换成异步队列
dispatch_async(dispatch_get_main_queue(), ^(void){
        NSLog(@"这里死锁了");    // 现在没有死锁
});
  • 换一个队列,不添加到主队列
dispatch_sync(dispatch_get_global_queue(0, 0), ^(void){
        NSLog(@"这里死锁了");   // 现在没有死锁
});

2、异步执行同步串行队列(任意队列)

dispatch_queue_t queue = dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);

NSLog(@"1");//任务1

dispatch_async(queue,^{

    NSLog(@"2");//任务2

    dispatch_sync(queue,^{

        NSLog(@"3");//任务3
    });

    NSLog(@"4");//任务4
});
NSLog(@"5");//任务5

// 1
// 5
// 2

首先任务1正常执行;
因为dispatch_async是一个异步线程,不会堵塞线程,所以任务5也正常执行;
进入dispatch_async里面,任务2可以直接执行;
然后是一个同步线程,并且queue是一个串行队列,遵循FIFO,此时同步线程会阻塞线程,任务3加入到queue队列中,但是任务4又是优先于3加入queue,所以任务3需要等待任务4执行完才执行,但是任务3又堵塞了线程,所以任务4也不能执行,这样相互堵塞造成死锁。

解决方案

  • 将异步线程和同步线程放在不同的队列
dispatch_queue_t queue = dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);

NSLog(@"1");//任务1

dispatch_async(queue,^{

    NSLog(@"2");//任务2

    dispatch_sync(dispatch_get_main_queue(),^{

        NSLog(@"3");//任务3
    });

    NSLog(@"4");//任务4
});
NSLog(@"5");//任务5

// 1
// 5
// 2
// 3
// 4
  • 将串行队列换成并发队列
dispatch_queue_t queue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_CONCURRENT);

NSLog(@"1");//任务1

dispatch_async(queue,^{

    NSLog(@"2");//任务2

    dispatch_sync(queue,^{

        NSLog(@"3");//任务3
    });

    NSLog(@"4");//任务4
});
NSLog(@"5");//任务5

// 1
// 5
// 2
// 3
// 4

3、堵塞主队列,同步主队列任务死锁

dispatch_async(dispatch_get_global_queue(0,0),^{
        
    NSLog(@"1");//任务1
        
    dispatch_sync(dispatch_get_main_queue(),^{
            
        NSLog(@"2");//任务2
            
    });
    NSLog(@"3");//任务3 
});
    
NSLog(@"4");//任务4
    
while(1){
        
}
NSLog(@"5");//任务5

// 4
// 1

首先是一个异步线程里的全局队列,不会堵塞,所以任务4可以执行;
异步线程里面任务1也可以执行,任务1、4顺序不固定;
然后主线程里的while循环堵塞主队列,但是异步线程的任务2也是加入到主队列里的,并且是在while循环任务之后,while堵塞,任务5无法执行,所以任务2也没法执行,任务2不能返回,那么任务3也不能执行。

  • 用一个并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

dispatch_async(queue,^{
        
    NSLog(@"1");//任务1
        
    dispatch_sync(queue,^{
            
        NSLog(@"2");//任务2
            
    });
   NSLog(@"3");//任务3a
        
});
    
NSLog(@"4");//任务4
    
while(1){
        
}
NSLog(@"5");//任务5

// 4
// 1
// 2
// 3

测试发现如果把queue换成一个自定义的串行队列,结果也只会打印4和1,任务2会死锁,所以可知全局队列是一个并发队列。

总结

造成死锁的原因是:在同一个串行的队列中,同步添加block。

相关文章

  • iOS GCD的死锁情况

    在iOS开发中,当遇到网络请求和耗时操作通常需要另外开一个子线程,然后需要刷新UI的时候回到主线程刷新;这里就要用...

  • iOS GCD死锁的情况和解决办法

    1、同步串行主队列 因为dispatch_sync是一个同步队列,所以会堵塞在这里,直至这个dispatch_sy...

  • 死锁 GCD 多线程

    死锁 GCD 多线程 Ios - LDSmallCat - 博客园 Ios中GCD死锁困扰很多人,分享一点个人经...

  • IOS开发 GCD产生死锁的总结

    在IOS开发中GCD的使用频率很高,但是使用不当,则会产生死锁,以下是我的对GCD产生死锁的总结。 了解死锁之前首...

  • GCD死锁情况

    造成死锁的情况分析 第一种是:主队列同步任务很容易造成死锁,因为主队列是在主线程空闲时才会调度队列中的任务在主线程...

  • 多线程相关之GCD、死锁、dispatch_barrier_as

    推荐阅读:备战2020——iOS全新面试题总结 GCD---同步/异步 ,串行/并发 死锁 GCD任务执行顺序 d...

  • ios GCD死锁

    死锁 1.定义 所谓死锁,通常指的是两个线程T1和T2都被卡住,并等待对方完成某些操作,T1等待T2完成,T2等待...

  • iOS:GCD死锁

    出现死锁的特点: 用 sync函数,向 当前 串行队列 添加任务。 举例:

  • 2019 iOS面试题-----进程、线程、多进程、多线程、任务

    2019 iOS面试题-----多线程相关之GCD、死锁、dispatch_barrier_async、dispa...

  • iOS-知识点

    五个案例让你明白GCD死锁:http://ios.jobbole.com/82622/ iOS开发中多线程间关于锁...

网友评论

      本文标题:iOS GCD死锁的情况和解决办法

      本文链接:https://www.haomeiwen.com/subject/rhjdvhtx.html