GCD面试题(一)

548 阅读2分钟

你知道下面的输出顺序是什么吗?

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_queue_t worker_queue = dispatch_queue_create("worker", DISPATCH_QUEUE_SERIAL);
    NSLog(@"0");
    
    dispatch_async(worker_queue, ^{
        NSLog(@"1");
    });
    
    dispatch_async(worker_queue, ^{
        NSLog(@"2");
    });
    
    dispatch_sync(worker_queue, ^{
        NSLog(@"3");
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"4");
        });
    });
    
    NSLog(@"5");
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"6");
    });
}

在查看答案之前可以先想一想你的答案,看看是否一样

点击查看答案
在回答这个问题之前,先说几个知识点
  1. 串行队列是先进先出的,先添加的任务一定是先执行的,主队列也是一个串行队列
  2. 当有一个同步任务要在串行队列中执行时,此时若队列中有其他任务未执行,则会先执行完其他任务之后,再执行这个同步任务
  3. dispatch_sync造成死锁的条件是dispatch_sync所处的队列和dispatch_sync要执行任务的队列是同一个队列,并且该队列是串行队列,如下
    dispatch_sync(worker_queue, ^{
        /// 当前队列是worker_queue,并且要把打印任务也要在worker_queue同步中执行
        dispatch_sync(worker_queue, ^{
            NSLog(@"33");
        });
        NSLog(@"3");
    });

接下来让我们分析一下代码

  1. 创建了一个串行队列worker_queue
  2. 打印0
  3. 添加一个异步任务(打印1)到worker_queue队列中
  4. 又添加一个异步任务(打印2)到worker_queue队列中
  5. 添加一个同步任务到worker_queue队列中
    1. 这里不会死锁,因为当前所处的队列是主队列,而任务执行的队列是worker_queue队列
    2. 由于是同步任务到串行队列,会按先进先出的顺序执行队列中的任务,依次打印1和2
    3. 然后执行同步任务打印3,并添加一个异步任务(打印4)到主队列中
  6. 打印5
  7. 添加一个异步任务(打印6)到主队列中
  8. 然后等主队列空闲之后,按照先进先出的顺序执行队列中的任务,依次打印4和6 所以答案是:0123546

截屏2021-06-12 下午10.17.43.png

如果你对上面的输出有疑问,强烈推荐你看看参考的这篇文章,对GCD源码的分析

如果本篇文章对你有帮助,能不能求个赞

参考

  1. 深入浅出GCD之dispatch_queue