1️⃣ 什么是优先级反转
优先级反转是指 高优先级任务被低优先级任务间接阻塞,导致系统调度违背期望优先级的现象。
- 高优先级任务本应先执行
- 低优先级任务占用资源(锁、队列、线程)
- 中等或低优先级任务阻塞高优先级任务 → “反转”
简单例子(概念)
高优先级任务H 需要锁A
低优先级任务L 已持有锁A
中等优先级任务M 不需要锁A
---------------------------------
H 等待 L 释放锁
M 占用 CPU
→ H 被间接阻塞 → 优先级反转
2️⃣ GCD 中优先级反转发生的条件
2.1 GCD 线程池机制
- GCD 使用 全局线程池调度不同 QoS 任务
- 高 QoS → 优先调度
- 低 QoS → 空闲线程执行
2.2 反转场景
场景示例:串行队列 + 高低 QoS 任务混用
let serialQueue = DispatchQueue(label: "serialQueue", qos: .utility)
// 低优先级任务
serialQueue.async(qos: .background) {
Thread.sleep(forTimeInterval: 5) // 模拟耗时操作
}
// 高优先级任务
serialQueue.async(qos: .userInitiated) {
print("高优先级任务执行")
}
分析
-
串行队列保证 FIFO
-
第一个任务是低 QoS (
.background) → 开始执行 -
第二个任务是高 QoS (
.userInitiated) → 被队列阻塞 -
问题:
- 高 QoS 任务不能越过队列前面的低 QoS 任务
- 高 QoS 任务被低 QoS 阻塞 → 优先级反转
✅ 特点:
- 队列类型:串行队列
- 队列内 QoS 不影响任务顺序 → 可能导致高 QoS 任务等待低 QoS
- GCD 在调度时可以 临时提升 QoS(QoS 继承机制)来缓解
2.3 与锁结合的反转
- 高 QoS 任务访问共享资源
- 低 QoS 任务持有锁
- 中等 QoS 任务占用 CPU
- GCD 的线程池可能没有足够线程 → 高 QoS 任务被间接阻塞
3️⃣ GCD 的优先级提升机制(QoS 继承)
-
GCD 使用 QoS 继承 避免优先级反转
-
规则:
- 当高 QoS 任务等待低 QoS 队列中的任务时
- 系统会临时将低 QoS 任务提升到高 QoS
-
这样高优先级任务不会被阻塞太久
上面串行队列示例:
- 高 QoS (
.userInitiated) 等待低 QoS (.background) - GCD 临时提升低 QoS 任务到
.userInitiated→ 加快执行 - 高 QoS 任务提前完成 → 减少优先级反转
4️⃣ 小结
| 概念 | 说明 |
|---|---|
| 优先级反转 | 高优先级任务被低优先级任务间接阻塞 |
| GCD 中发生 | 串行队列任务顺序、锁占用、线程池资源不足 |
| 典型场景 | 串行队列低 QoS 任务在前,高 QoS 任务排队等待 |
| 避免方式 | QoS 继承机制、合理队列设计、避免高低 QoS 混用串行队列 |
💡 一句话总结:
GCD 中的优先级反转发生在高 QoS 任务被低 QoS 任务阻塞时,典型场景是串行队列或共享资源,GCD 通过 QoS 继承机制临时提升低 QoS 任务来缓解。