1-29.【GCD】什么是优先级反转?在 GCD 中如何发生?

4 阅读2分钟

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("高优先级任务执行")
}

分析

  1. 串行队列保证 FIFO

  2. 第一个任务是低 QoS (.background) → 开始执行

  3. 第二个任务是高 QoS (.userInitiated) → 被队列阻塞

  4. 问题

    • 高 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 任务来缓解。