24.任务与队列的几个面试题

一、 我们先看个面试题热热身

面试题一 - 串行队列

下面的打印输出会是什么样?

/// 串行队列
dispatch_queue_t queue = dispatch_queue_create("Ryukie.Queue", DISPATCH_QUEUE_SERIAL);

dispatch_async(queue, ^{
    NSLog(@"1");
});

dispatch_async(queue, ^{
    NSLog(@"2");
});

dispatch_sync(queue, ^{
    NSLog(@"3");
});

NSLog(@"0");

dispatch_async(queue, ^{
    NSLog(@"7");
});

dispatch_async(queue, ^{
    NSLog(@"8");
});

dispatch_async(queue, ^{
    NSLog(@"9");
});
  • A: 1230789

  • B: 1237890

  • C: 3120789

  • D: 2137890

分析

  • 3 的同步任务,阻碍了0 7 8 9 的异步任务,故 3 一定在 0 7 8 9 前。

  • 7 8 9 三个任务的顺序不一定,但在 0 之后。

  • 1 2 3 的顺序不一定。

满足上面几点的答案为:A C

这里很可能会觉得 12 一定在 3 之前,要清楚 3 阻塞的是 3 之后的任务,123 的顺序并不一定。

如果是异步队列呢?

123 789 都是乱序的

面试题二 - while

输出会是多少呢?

__block int num = 0;

while (num < 10) {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        num++;
    });
}

printf("%d\n", num);
  • 由于 num++ 是异步的,所以执行的次数大于等于 10

  • 由于 while 循环条件阻塞,打印一定在 num >= 10 条件下输出

  • 输出大于等于 10

面试题三 - for

输出会是多少呢?

__block int num = 0;

for (int i = 0; i < 1000; i++) {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        num++;
    });
}

printf("%d\n", num);
  • for 循环保证了循环次数,一定是1000次

  • for循环不会阻塞后面的 printf 函数执行

  • 故:打印结果小于等于 1000(可能打印的时候还有 ++ 任务未执行完)

面试题三 - 死锁

下面几个分别输出是什么

- (void)deadLock1 {
    //    dispatch_queue_t queue = dispatch_queue_create("Ryukie", NULL);
    dispatch_queue_t queue = dispatch_queue_create("Ryukie", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1");
    dispatch_async(queue, ^{
        NSLog(@"2");
        dispatch_sync(queue, ^{
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    NSLog(@"5");
}
  • 输出

    • 1,5,2 死锁

  • 分析

    • 串行队列

    • async 放入队列一个 blockA 任务

    • blockA 内部又向队列内部添加了一个 blockB 任务

    • 队列需要等待 blockA 执行完毕再执行下一个任务

    • 但是添加 blockB 时,sync 阻断了 blockA 内部的执行,导致 blockA 无法执行完成

    • 所以死锁了

- (void)deadLock2 {
    dispatch_queue_t queue = dispatch_queue_create("Ryukie", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"1");
    dispatch_async(queue, ^{
        NSLog(@"2");
        dispatch_sync(queue, ^{
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    NSLog(@"5");
}
  • 输出

    • 1,5,2,3,4

- (void)deadLock3 {
    //    dispatch_queue_t queue = dispatch_queue_create("Ryukie", NULL);
    dispatch_queue_t queue = dispatch_queue_create("Ryukie", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1");
    dispatch_async(queue, ^{
        NSLog(@"2");
        dispatch_sync(queue, ^{
            NSLog(@"3");
        });
    });
    NSLog(@"5");
}
  • 输出

    • 1,5,2 死锁

  • 和第一个一样

- (void)deadLock4 {
    dispatch_queue_t queue = dispatch_queue_create("Ryukie", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1");
    NSLog(@"2");
    dispatch_sync(queue, ^{
        NSLog(@"3");
    });
    NSLog(@"4");
    NSLog(@"5");
}
  • 输出

    • 1,2,3,4,5

  • 串行队列

    • 同步任务,没有阻塞队列内任务的执行,没有死锁,正常执行

    • 所以 同步任务 + 串行队列 不一定死锁

二、 任务与队列

Last updated