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

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

#### 面试题一 - 串行队列

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

```objc
/// 串行队列
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

输出会是多少呢？

```C++
__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](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F918274adaa803a90158d815601fa2bca33a9e9ad.png?generation=1630850444114275\&alt=media)

#### 面试题三 - for

输出会是多少呢？

```C++
__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](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2F17390cc2a836759bdfe3dd0c65f164317812efe6.png?generation=1630850445156306\&alt=media)

#### 面试题三 - 死锁

下面几个分别输出是什么

```C++
- (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 无法执行完成
  * 所以死锁了

```C++
- (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

```C++
- (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 死锁
* 和第一个一样

```C++
- (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
* 串行队列
  * 同步任务，没有阻塞队列内任务的执行，没有死锁，正常执行
  * 所以 同步任务 + 串行队列 不一定死锁

### 二、 任务与队列

![任务与队列](https://4193904735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MI8JgbGh3U6X_oedqkm%2Fsync%2Fc716ce87790dce8fb98ff7c38513251bbfcaf9c6.png?generation=1630850446003419\&alt=media)
