Links

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
01

面试题三 - 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(可能打印的时候还有 ++ 任务未执行完)
02

面试题三 - 死锁

下面几个分别输出是什么
- (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
  • 串行队列
    • 同步任务,没有阻塞队列内任务的执行,没有死锁,正常执行
    • 所以 同步任务 + 串行队列 不一定死锁

二、 任务与队列

任务与队列