GCD dead lock 试分析

2018-03-28  本文已影响0人  nunca

一、dispatch queue 种类
1.serial dispatch queue : 等待现在执行中的处理结束,同时执行的处理数只能有1个

// 新建一个serial dispatch queue
dispatch_queue_t serialQueue = dispatch_queue_create("serial.queue.Async", NULL);

// 获取main dispatch queue
dispatch_queue_t mainQueue = dispatch_get_main_queue();

2.concurrent dispatch queue : 不等待现在执行中的处理结束,可同时进行多个处理,由当前系统的状态决定并行执行的处理数

// 新建一个concurrent dispatch queue
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrent.queue.Sync", DISPATCH_QUEUE_CONCURRENT);

// 获取global dispatch queue
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

二、dispatch_sync 和dispatch_async 函数
1.dispatch_sync:即为同步,也就是将指定的block同步追加到指定的dispatch queue中,在追加block结束之前,dispatch_sync函数会一直等待

  dispatch_queue_t queue = dispatch_queue_create("concurrent.queue.Async", DISPATCH_QUEUE_CONCURRENT);
  dispatch_sync(queue, ^{
      for (int i = 0 ; i < 5; i ++ ) {NSLog(@"--sync----task1----%d",i);}
  });
  dispatch_sync(queue, ^{
      for (int i = 0 ; i < 5; i ++ ) {NSLog(@"--sync----task2----%d",i);}
  });
  dispatch_sync(queue, ^{
      for (int i = 0 ; i < 5; i ++ ) {NSLog(@"--sync----task3----%d",i);}
  });

如下打印,task1、task2、task3 按顺序依次执行,在task1未结束之前dispatch_sync函数会进行等待

2018-03-28 16:15:40.658351+0800 Nunca[8534:179897] --sync----task1----0
2018-03-28 16:15:40.658539+0800 Nunca[8534:179897] --sync----task1----1
2018-03-28 16:15:40.658802+0800 Nunca[8534:179897] --sync----task1----2
2018-03-28 16:15:40.658923+0800 Nunca[8534:179897] --sync----task1----3
2018-03-28 16:15:40.659021+0800 Nunca[8534:179897] --sync----task1----4
2018-03-28 16:15:40.659511+0800 Nunca[8534:179897] --sync----task2----0
2018-03-28 16:15:40.659939+0800 Nunca[8534:179897] --sync----task2----1
2018-03-28 16:15:40.660690+0800 Nunca[8534:179897] --sync----task2----2
2018-03-28 16:15:40.661190+0800 Nunca[8534:179897] --sync----task2----3
2018-03-28 16:15:40.661645+0800 Nunca[8534:179897] --sync----task2----4
2018-03-28 16:15:40.662288+0800 Nunca[8534:179897] --sync----task3----0
2018-03-28 16:15:40.662472+0800 Nunca[8534:179897] --sync----task3----1
2018-03-28 16:15:40.663441+0800 Nunca[8534:179897] --sync----task3----2
2018-03-28 16:15:40.664091+0800 Nunca[8534:179897] --sync----task3----3
2018-03-28 16:15:40.664344+0800 Nunca[8534:179897] --sync----task3----4

2.dispatch_async:即为非同步,就是将指定的block非同步地追加到指定的dispatch queue中,dispatch_async函数不做等待

  dispatch_queue_t queue = dispatch_queue_create("concurrent.queue.Async", DISPATCH_QUEUE_CONCURRENT);
  dispatch_async(queue, ^{
      for (int i = 0 ; i < 5; i ++ ) {NSLog(@"--Async----task1----%d",i);}
  });
  dispatch_async(queue, ^{
      for (int i = 0 ; i < 5; i ++ ) {NSLog(@"--Async----task2----%d",i);}
  });
  dispatch_async(queue, ^{
      for (int i = 0 ; i < 5; i ++ ) {NSLog(@"--Async----task3----%d",i);}
  });

如下打印,task1、task2、task3 并列同步执行,不用等待task1执行完成便可开始执行task2、task3

2018-03-28 16:13:25.517938+0800 Nunca[8470:178300] --Async----task2----0
2018-03-28 16:13:25.517938+0800 Nunca[8470:178303] --Async----task1----0
2018-03-28 16:13:25.517957+0800 Nunca[8470:178299] --Async----task3----0
2018-03-28 16:13:25.518208+0800 Nunca[8470:178300] --Async----task2----1
2018-03-28 16:13:25.518219+0800 Nunca[8470:178303] --Async----task1----1
2018-03-28 16:13:25.518420+0800 Nunca[8470:178300] --Async----task2----2
2018-03-28 16:13:25.518420+0800 Nunca[8470:178299] --Async----task3----1
2018-03-28 16:13:25.518495+0800 Nunca[8470:178300] --Async----task2----3
2018-03-28 16:13:25.518524+0800 Nunca[8470:178303] --Async----task1----2
2018-03-28 16:13:25.518674+0800 Nunca[8470:178299] --Async----task3----2
2018-03-28 16:13:25.518753+0800 Nunca[8470:178303] --Async----task1----3
2018-03-28 16:13:25.519352+0800 Nunca[8470:178300] --Async----task2----4
2018-03-28 16:13:25.519569+0800 Nunca[8470:178299] --Async----task3----3
2018-03-28 16:13:25.519778+0800 Nunca[8470:178303] --Async----task1----4
2018-03-28 16:13:25.520527+0800 Nunca[8470:178299] --Async----task3----4

虽然实际写代码时 serial queue + sync task 的组合基本不会出现,但还是可以记录下此种情况下容易导致发生的死锁问题。

casa 1 :

    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"dead lock");
    });

如上,试分析:
1、dispatch_sync()函数在主线程执行,传入的block也需要添加到主线程并在主线程执行,因此主线程现在有两个任务需要执行 :task1 dispatch_sync() 、 task2 block() ;
2、由于main dispatch queue 为serial dispatch queue ,所以需要等待task1处理结束才能处理task2;
3、对于task1 dispatch_sync函数,由于sync代表的同步性,必须等到追加的block(task2)执行结束 dispatch_sync函数才会返回,在追加block结束之前,dispatch_sync函数会一直等待;

所以此时的情况是:task1执行完成 task2才能开始执行、task2结束task1才能执行完成,死锁便出现。

case 2 :

    dispatch_queue_t serialQueue = dispatch_queue_create("serial.queue.Async", NULL);
    dispatch_async(serialQueue, ^{ // block1
        dispatch_sync(serialQueue, ^{ //block2
            NSLog(@"dead lock");
        });
    });

试分析:
1、在主线程中执行dispatch_async()函数,在serialQueue中需要执行的任务有:task1 block1() 、task2 block2() ;
2、block1中内容即为dispatch_sync()函数,因此task1 实际为dispatch_sync() ;
3、同case1

上一篇下一篇

猜你喜欢

热点阅读