You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么从并发队列异步调用DispatchQueue.main.sync成功,同步调用却失败?

GCD 队列调用死锁差异原因解析

核心前提概念

  • sync 提交任务的核心规则:将任务提交到目标队列后,会阻塞当前调用所在的线程/队列,直到目标队列完成该任务的执行才会返回,继续执行后续逻辑
  • async 提交任务的核心规则:将任务提交到目标队列后立刻返回,不会阻塞当前线程/队列的后续执行
  • DispatchQueue.main 是串行主队列:所有提交到主队列的任务必须按顺序在主线程上执行,主线程是主队列的唯一执行线程

第一种场景:background.async 调用可正常执行的原因

你首先创建了优先级为 .background 的串行队列:

let background = DispatchQueue(label: "backgroundQueue",
                               qos: .background,
                               attributes: [],
                               autoreleaseFrequency: .inherit,
                               target: nil)

执行如下代码时:

background.async {
    DispatchQueue.main.sync {
        print("Hello from background async")
    }
}

执行流程:

  1. 主线程调用 background.async,将闭包任务提交到background队列后立刻返回,不会阻塞主线程,主队列可以正常处理后续提交的任务
  2. background队列拿到系统分配的线程执行提交的闭包
  3. 闭包内调用 DispatchQueue.main.sync,将打印任务提交到主队列,同时阻塞background队列的执行线程,等待打印任务完成
  4. 此时主线程处于空闲状态,直接执行主队列中的打印任务,执行完成后向background队列的sync调用返回
  5. background队列的闭包继续执行直到结束,整个流程没有出现互相等待的情况,所以可以正常运行

第二种场景:background.sync 触发死锁的原因

执行如下代码时:

background.sync {
    DispatchQueue.main.sync {
        print("Hello from background sync")
    }
}

执行流程走到第二步就会出现循环等待:

  1. 主线程调用 background.sync,将闭包任务提交到background队列,直接阻塞主线程,必须等待background队列的闭包完全执行完成,主线程才会恢复,继续处理主队列的任务
  2. background队列拿到线程执行闭包,调用 DispatchQueue.main.sync,将打印任务提交到主队列,同时阻塞background队列的执行线程,等待主队列完成打印任务的执行
  3. 此时形成死锁循环:
    • 主线程被 background.sync 阻塞,无法执行主队列中新增的打印任务
    • background队列的闭包被 DispatchQueue.main.sync 阻塞,无法执行完成向主线程返回
      两边都在等待对方释放资源,永远无法继续执行,因此触发死锁。

内容的提问来源于stack exchange,提问作者Rozaliia Amirova

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 19:24:05