1️⃣ 核心结论
Barrier 只对自定义并发队列有效,是因为 barrier 的实现依赖队列内部的任务调度控制,而全局队列和串行队列的调度机制不允许修改或者插入“屏障”。
换句话说:
- 串行队列天然保证同一时间只执行一个任务 → barrier 多余
- 全局队列是共享的并发队列 → barrier 无法保证独占执行
2️⃣ 串行队列为什么不需要 barrier?
串行队列特点:
- 同一时间只允许一个任务执行
- 队列内部天然 FIFO
串行队列:
task1 -> task2 -> task3
-
即使没有 barrier:
- task1 完成后才会执行 task2
- task2 完成后才执行 task3
✅ barrier 对串行队列完全无意义
3️⃣ 全局并发队列为什么不支持 barrier?
全局队列特点:
- 系统管理的共享队列
- 线程池是全局共享的
- 任务来自不同来源(App 内的多个 dispatch queue)
如果你在 global queue 上使用 barrier:
-
无法保证“前面任务全部完成”
- 因为 global queue 的任务是多来源的
- 你无法控制前面到底有哪些任务正在执行
-
barrier 执行时无法独占线程池
- global queue 线程可能正在执行其他队列的任务
- 无法阻塞其他人的线程而只执行 barrier
本质原因:Barrier 需要“屏障前的任务可控,屏障期间独占线程,屏障后继续并发” ,这是自定义并发队列才能做到的。
4️⃣ 自定义并发队列如何支持 barrier
自定义并发队列特点:
- 队列任务 只来自一个队列(你的 queue)
- GCD 可以在内部维护一个 isExecuting 或正在执行计数器
实现机制:
-
提交 barrier 任务:
- 队列先等待当前队列内部的所有任务完成
- 在 barrier 任务执行期间,不派发新的任务
-
执行 barrier:
- 独占执行(可能在现有线程或新线程上)
-
Barrier 完成:
- 恢复派发后续任务
- 后续任务继续并发执行
⚠️ 关键:这个控制仅在 自定义并发队列 内部可控
- 全局队列:任务来自不同队列,无法保证屏障前任务全部完成
- 串行队列:本身就是单任务串行,屏障多余
5️⃣ 总结
| 队列类型 | 是否支持 barrier | 原因 |
|---|---|---|
| 串行队列 | ❌ | 天然串行,屏障多余 |
| 全局并发队列 | ❌ | 任务来源多,无法独占线程或保证前置任务完成 |
| 自定义并发队列 | ✅ | 队列可控,GCD 内部可以实现 barrier 屏障机制 |
一句话总结:Barrier 的语义是“队列内部独占执行”,而只有自定义并发队列,任务来源可控、线程可调度,才能实现这个语义。
👉 追问:在 global queue 上用 barrier 会发生什么?
在 global queue(全局并发队列) 上使用 dispatch_barrier,结果和你想象的屏障语义 完全不一样。
一句话核心结论:
在 global queue 上使用 barrier 并不会创建独占屏障,任务只是像普通 async 一样提交执行,不保证前面任务完成或屏障期间独占线程。
下面详细拆开:
1️⃣ global queue 的特点
- 是 系统管理的共享并发队列
- 线程池是全局共享的
- 任务可能来自多个不同队列或系统组件
- 你无法控制“前面到底有哪些任务正在执行”
2️⃣ barrier 的语义
在自定义并发队列:
- 屏障任务 必须等待前面队列内部任务完成
- 屏障期间 独占执行
- 屏障任务完成后,后续任务继续并发执行
在 global queue 上:
- 你提交的 barrier 任务只是普通 async 任务
- barrier 标记被忽略,系统不会等待前面的 global queue 任务
- barrier 任务可能 与其他 global queue 任务同时执行
3️⃣ 举例
let global = DispatchQueue.global(qos: .default)
global.async { print("A") }
global.async { print("B") }
global.async(flags: .barrier) { print("Barrier") }
global.async { print("C") }
执行可能结果:
A B Barrier C
A Barrier B C
Barrier A B C
- barrier 不会保证独占
- 前后顺序不确定
- 与普通 async 完全一样
4️⃣ 为什么会这样
-
barrier 的实现依赖 可控的队列任务来源 + 内部调度状态
-
global queue 任务来源多、不可控
-
GCD 无法保证:
- 前面任务完成
- 屏障任务独占线程
⚠️ 所以官方文档明确说明:
“Barrier only works on custom concurrent queues. Applying a barrier on a global queue has no effect.”
5️⃣ 总结
- global queue + barrier = barrier 标记被忽略
- 任务行为等同普通
async - 不要在全局队列上依赖 barrier 实现读写屏障
💡 实践建议:
- 共享资源的并发读 + 写屏障 → 使用自定义并发队列 + barrier
- 全局队列只适合普通并发任务,不用于屏障控制