1️⃣ 串行语义的定义
串行队列保证:同一时间最多只有一个任务在执行,任务严格按提交顺序(FIFO)运行。
- FIFO 顺序:先提交的任务先执行
- 互斥:不会同时执行多个任务
- 线程数量不固定 → 可能不同任务跑在不同线程上
2️⃣ 串行语义不是线程绑定
- 串行队列不要求“只用一条线程”
- GCD 只保证**“同一时间最多执行一个 block”**
- 不同任务可以在不同线程上运行,只要不重叠执行就符合串行语义
3️⃣ GCD 内部机制(state machine)
串行队列实现串行语义的核心手段是:
-
队列状态:
isExecuting或内部标记:当前是否有任务在执行
-
FIFO 队列存储任务:
- 每个 async / sync 提交的 block 都被封装成任务对象,排入队列尾
-
调度逻辑:
当队列空闲(
isExecuting == false)时:- 取队列头任务
- 派发给 target queue(可能是 global queue)
- 设置
isExecuting = true
当任务完成:
isExecuting = false- 取下一个任务执行
⚠️ 关键点:串行控制在队列层,而不是线程层
4️⃣ 示例流程
假设串行队列 serial 提交了三个任务 A、B、C:
提交 A -> 队列:[A] -> 空闲,A 派发 -> isExecuting=true
提交 B -> 队列:[B]
提交 C -> 队列:[B,C]
-
执行 A
-
完成 A:
- 更新队列状态
- 派发 B
-
执行 B
-
完成 B:
- 派发 C
-
执行 C
-
完成 C:
- 队列空闲
始终保证同时只有一个任务执行
5️⃣ Target Queue 的作用
-
串行队列通常有一个 target queue
- 可以是全局并发队列(global queue)
- 也可以是另一个串行队列
-
串行语义仍然保持,因为 队列层的状态机只允许一个任务被派发
⚠️ 即使 target 是并发队列,也不会破坏串行语义
6️⃣ 对 sync 和 async 的影响
-
async:
- 提交任务后立即返回
- 队列状态机负责按顺序派发
-
sync:
- 当前线程可能直接执行任务(fast-path)
- 队列状态机仍然保证同一时间只有一个任务执行
7️⃣ 总结机制(精炼版)
GCD 保证串行语义的核心:
-
每个串行队列维护任务队列 + 执行状态
-
提交任务:
- 放入 FIFO 队列
-
队列空闲时:
- 派发队头任务
- 设置“正在执行”标记
-
任务完成:
- 清除标记
- 派发下一个任务
-
整个过程中,永远只允许一个任务执行
重点:串行语义靠队列内部调度状态机实现,而不是靠线程数量或线程锁。