iOS gcd线程死锁问题

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

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

场景一:

#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,然后程序奔溃


iOS gcd线程死锁问题_第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,程序正常运行


iOS gcd线程死锁问题_第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,程序正常运行


iOS gcd线程死锁问题_第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),程序正常运行


iOS gcd线程死锁问题_第4张图片
截屏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)程序奔溃,产生死锁


iOS gcd线程死锁问题_第5张图片
截屏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.如果将该串行队列改为并发队列这三种情况都不会产生死锁!

你可能感兴趣的:(iOS gcd线程死锁问题)