iOS Developer

GCD队列和死锁解析

2016-11-23  本文已影响185人  bluajack

GCD核心概念

队列(Queue)详解

队列使用

dispatch_get_main_queue()
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)//第二个参数无用,苹果用0
#define DISPATCH_QUEUE_PRIORITY_HIGH 2  //优先级最高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 //一般默认使用这个
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN //优先级最低
// 串行队列的创建方法
dispatch_queue_t queue= dispatch_queue_create("bluajack", DISPATCH_QUEUE_SERIAL);
// 并发队列的创建方法
dispatch_queue_t queue= dispatch_queue_create("bluajack", DISPATCH_QUEUE_CONCURRENT);

GCD函数创建任务

// 同步执行任务创建方法
dispatch_sync(queue, ^{ NSLog(@"%@",[NSThread currentThread]); // 这里放任务代码});
// 异步执行任务创建方法
dispatch_async(queue, ^{ NSLog(@"%@",[NSThread currentThread]); // 这里放任务代码});

- 函数和队列组合方式
 - ```objc
   同步执行 + 串行队列     (不会开启子线程,串行执行任务)
   同步执行 + 并发队列     (不会开启子线程,串行执行任务)
   异步执行 + 串行队列     (开启子线程,串行执行任务)
   异步执行 + 并发队列     (开启子线程,并行执行任务)
   
    //特殊队列- 主队列
    同步执行 + 主队列       (不会开启子线程,串行执行任务)
    异步执行 + 主队列       (不会开启子线程,串行执行任务)
    ```
- 归纳
 - 1.同步GCD函数执行任务,无论添加的是串行队列还是并发队列,都不会创建子线程,但都会在创建任务后,立刻在当前线程依次按队列先进先出(FIFO)顺序执行任务。
 - 2.主队列是一个特殊的队列,无论是GCD同步函数还是异步函数执行任务,都不会创建子线程。


##分析主队列 + 异步
- 先贴代码和控制台信息
- ```objc
 - (void)viewDidLoad {
    [super viewDidLoad];
    
     NSLog(@"1");
    
    //同步GCD函数,无论是串行队列还是并发队友,都不会创建子线程,但都会在创建后,立刻在当前线程依次按队列FIFO顺序执行任务。
    //主队列是一个特殊的队列,无论是GCD同步函数还是异步函数,都不会创建子线程
    //所以只有在主线程执行完主队列里面的内容,空闲时,才能去执行你创建的队列。
    dispatch_async(dispatch_get_main_queue(), ^{
        for (int i = 0; i<5; i++) {
            NSLog(@"222222222%@",[NSThread currentThread]);
        }
    });����
    
    for (int i = 0; i<5; i++) {
        NSLog(@"3");
    }
}
 - (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    
    for (int i = 0; i<5; i++) {
        NSLog(@"4");
    }
}
 - (void)viewDidAppear:(BOOL)animated{
    TestViewController *VC = [[TestViewController alloc] init];
    
    //一直到modal方法结束后,才能在主线程去执行你创建的队列
    //我猜测modal方法内部,是执行了VC控制器的loaView懒加载方法,初始化view,一并执行了viewDidLoad方法
    //交给系统GPU去渲染,然后此时CPU得到空闲,就会去执行我在本控制器内部用GCD在主队列中创建的任务,
    //然后我创建的任务执行完毕,就会继续执行主队列的内容,GPU渲染完毕,通知CPU进行视图的显示,
    //此时就会调用VC的viewWillAppear的代理方法。
    [self presentViewController:VC animated:YES completion:nil];
}

**2016-11-23 17:06:23.207 test-GCD死锁[14103:166127] 1
**2016-11-23 17:06:23.207 test-GCD死锁[14103:166127] 3
**2016-11-23 17:06:23.207 test-GCD死锁[14103:166127] 3
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 3
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 3
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 3
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 4
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 4
**2016-11-23 17:06:23.208 test-GCD死锁[14103:166127] 4
**2016-11-23 17:06:23.209 test-GCD死锁[14103:166127] 4
**2016-11-23 17:06:23.209 test-GCD死锁[14103:166127] 4
**2016-11-23 17:06:23.213 test-GCD死锁[14103:166127] -[TestViewController viewDidLoad]
**2016-11-23 17:06:23.577 test-GCD死锁[14103:166127] 222222222<NSThread: 0x7f8f84507dd0>{number = 1, name = main}
**2016-11-23 17:06:23.578 test-GCD死锁[14103:166127] 222222222<NSThread: 0x7f8f84507dd0>{number = 1, name = main}
**2016-11-23 17:06:23.578 test-GCD死锁[14103:166127] 222222222<NSThread: 0x7f8f84507dd0>{number = 1, name = main}
**2016-11-23 17:06:23.578 test-GCD死锁[14103:166127] 222222222<NSThread: 0x7f8f84507dd0>{number = 1, name = main}
**2016-11-23 17:06:23.578 test-GCD死锁[14103:166127] 222222222<NSThread: 0x7f8f84507dd0>{number = 1, name = main}
**2016-11-23 17:06:23.580 test-GCD死锁[14103:166127] -[TestViewController viewWillAppear:]

- 把上述代码创建的GCD函数内部的代码块的for循坏,加到10000次,你就能很明显的感觉到页面跳转的延迟,这就造成主线程的阻塞。


##GCD死锁
- 典型例子:在主线程中用GCD创建同步 + 主队列函数
- ```objc
    - (void)viewDidLoad {
      [super viewDidLoad];
       NSLog(@"1");
       dispatch_async(dispatch_get_main_queue(), ^{
          NSLog(@"2%@",[NSThread currentThread]);
       });���� 
       NSLog(@"3"); 
}

输出结果为:1 。这个程序就是典型的死锁,只打印了“1”一行,就再也没有响应了,已经造成了GCD死锁。


下班了,具体分析,你们可以看下面这篇文章,比较详细。
http://www.jianshu.com/p/bbabef8aa1fe

上一篇 下一篇

猜你喜欢

热点阅读