美文网首页程序员
iOS gcd线程死锁问题

iOS gcd线程死锁问题

作者: Good_Citizen | 来源:发表于2020-07-08 11:22 被阅读0次

同步异步决定是否具备开启线程的能力
串行并行决定代码执行的先后顺序

先看下这几个场景,每个场景中的代码执行后会打印什么,为什么?

场景一:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self test1];
}

-(void)test1{
//    主队列 串行队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"任务1");
//    同步任务
    dispatch_sync(queue, ^{
        NSLog(@"任务2");
    });
    NSLog(@"任务3");
}

@end

答案:会打印任务1,然后程序奔溃


截屏2020-07-06 14.23.24.png

原因:由于整个viewDidLoad方法是先加入到主队列中的,然后将viewDidLoad方法中的代码从队列中取出来一步步执行,当执行到dispatch_sync时,就会将任务2的代码加入到主队列中,由于主队列是串行队列,所以必须要让先从主队列中取出来的viewDidLoad方法中的所有代码执行完才能取出后面加入到主队列中的任务2代码来执行,但dispatch_sync同步任务的特点是立即要在当前线程也就是主线程中执行任务2中的代码,这样就形成了互相等待的僵局,这就是死锁!

场景二:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self test1];
}

-(void)test1{
//    主队列 串行队列
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"任务1");
//    异步任务
    dispatch_async(queue, ^{
        NSLog(@"任务2");
    });
    NSLog(@"任务3");
}

@end

答案:结果打印任务1、任务3、任务2,程序正常运行


截屏2020-07-06 14.25.33.png

原因:在执行主队列中的viewDidLoad方法时,碰到dispatch_async时也会将任务2中的代码加入到主队列中,但不同的是dispatch_async并不要求立马执行,可以延后执行,这样viewDidLoad方法执行完后再从主队列中取出刚加入的任务2代码,就不会造成互相等待的情况了

场景三:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self test1];
}

-(void)test1{
//    手动创建的串行队列
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"任务1");
//    同步任务
    dispatch_sync(queue, ^{
        NSLog(@"任务2");
    });
    NSLog(@"任务3");
}

答案:结果打印任务1、任务2、任务3,程序正常运行


截屏2020-07-06 14.38.29.png

原因:在执行主队列中的viewDidLoad方法时,碰到dispatch_sync时就会将任务2中的代码加入到手动创建的串行队列中,同步任务会让任务中代码立即执行,由于任务2中的代码是在其他的串行队列中执行,和主线程没有关系,所以就优先执行任务2中的代码,最后执行任务3

场景四:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self test1];
}

-(void)test1{
//    手动创建的串行队列
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"任务1");
//    异步任务
    dispatch_async(queue, ^{
        NSLog(@"任务2");
    });
    NSLog(@"任务3");
}

答案:结果打印任务1、任务2、任务3(或者任务1、任务3、任务2),程序正常运行


截屏2020-07-06 14.46.20.png

原因:在执行主队列中的viewDidLoad方法时,碰到dispatch_async时就会将任务2中的代码加入到手动创建的串行队列中,由于任务2和任务3不在同一个队列中,而且任务2又是异步执行,会创建子线程,所以任务2和任务3是并发执行的,因此打印结果会有两种情况

场景五:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self test1];
}

-(void)test1{
//    手动创建的串行队列
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"任务1");
//    异步任务
    dispatch_async(queue, ^{  // block1
        NSLog(@"任务2");
//        同步任务
        dispatch_sync(queue, ^{  // block2
            NSLog(@"任务3");
        });
        NSLog(@"任务4");
    });
    NSLog(@"任务5");
}

答案:结果打印任务1、任务2(或者任务1、任务5、任务2)程序奔溃,产生死锁


截屏2020-07-06 15.01.55.png

原因:在执行主队列中的viewDidLoad方法时,碰到dispatch_async时就会将block1中的代码加入到手动创建的串行队列中,由于任务2和任务5不在同一个队列中,而且任务2又是异步执行,会创建子线程,所以任务2和任务5是并发执行的,因此打印结果会有两种情况,当block1在执行任务2的时候,碰到dispatch_sync就会将block2加入到当前串行队列queue中,由于dispatch_sync是同步任务,需要立即执行blcok2中的代码,但queue是串行队列,需要将已经取出来执行的block1的代码执行完才能执行串行队列中的下一个任务也就是block2,这样就互相等待造成死锁!

结论:

正在执行的代码是从串行队列中取出来的,而且再次向该串行队列中加入同步任务就会造成死锁!两者缺一不可!

1.如果向该串行队列中加入的是异步任务
2.如果将任务加入到其他队列
3.如果将该串行队列改为并发队列这三种情况都不会产生死锁!

相关文章

  • 死锁 GCD 多线程

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

  • iOS gcd线程死锁问题

    同步异步决定是否具备开启线程的能力串行并行决定代码执行的先后顺序 先看下这几个场景,每个场景中的代码执行后会打印什...

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

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

  • iOS-知识点

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

  • iOS多线程梳理-GCD(3)

    上一篇 iOS多线程梳理-GCD死锁 GCD栅栏函数 仅在自己创建的并发队列上有效,在全局(Global)并发队列...

  • iOS多线程梳理-GCD死锁

    上一篇 iOS多线程梳理-GCD GCD死锁探讨 先看一个简单程序: 可以看出,viewDidLoad执行了第一句...

  • GCD同步阻塞原理

    GCD因为功能强大,操作简便,成为苹果官方推荐使用的多线程API。然而GCD也难只要逃涉及多线程就会遇到的死锁问题...

  • iOS多线程:『GCD』详尽总结

    iOS多线程:『GCD』详尽总结 iOS多线程:『GCD』详尽总结

  • 多线程

    /*多线程问题 :1.死锁,2,抢占资源线程安全3,消耗大量内存GCD 把任务添加到 DispathQueue分为...

  • 多线程GCD和NSOpreation

    /*多线程问题 :1.死锁,2,抢占资源线程安全3,消耗大量内存GCD 把任务添加到 DispathQueue分为...

网友评论

    本文标题:iOS gcd线程死锁问题

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