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

Swift实现线程安全数组时,调用自定义DispatchQueue同步方法如何避免主线程死锁?

多线程数组读写的死锁修复方案

死锁触发的核心逻辑

当前实现的并发队列同步读逻辑本身不存在和主队列的必然耦合,出现死锁本质是出现了跨队列的循环同步等待:

  • 自定义annotationsQueue的块(读或屏障写)内部,存在DispatchQueue.main.sync的等待逻辑,需要等主队列任务执行完才能释放队列
  • 主队列上的执行流程,刚好又同步访问annotations属性,需要等annotationsQueue的锁释放才能返回结果
    两边互相等对方释放资源,就会直接卡死,和观察到的主队列流程中触发死锁的堆栈表现完全匹配。

两种应对方案的对比与适用场景

  • 不推荐强制将annotationsQueue绑定后台线程
    自定义并发队列本身是独立的执行上下文,不存在必须依赖特定线程才能运行的逻辑。单纯给队列加QoS标签或者强制切后台线程,根本解决不了循环等待的本质问题,反而会额外增加线程调度的开销。只要保证annotationsQueue上的所有执行块(同步读、屏障写)内部,永远不会用sync的方式等待主队列任务完成,哪怕在主队列上同步调用读属性,也不会触发死锁。
  • 按需调整主队列的调用逻辑
    如果主队列上的任务本身不需要同步拿到标注数组的结果,完全可以把同步读改成异步取数逻辑,在拿到数组副本的回调里再做UI更新,从根源上去掉主队列上的同步等待节点。但如果你的渲染逻辑必须同步拿到最新的标注数组才能完成布局,硬改成异步读反而会引入数组状态不同步的额外bug。

读属性实现的优化

当前的读属性代码存在强解包的冗余风险,可以简化成更安全的形式,不改变原有并发逻辑:

private var annotations: [MapAnnotation] {
    annotationsQueue.sync { unsafeAnnotations }
}

必须规避的高风险写法

  • 不要在annotationsQueue的屏障写块里调用DispatchQueue.main.sync,这是触发当前死锁的最常见原因
  • 不要为了简化队列逻辑把annotationsQueue替换为主队列,否则所有数组操作都会阻塞UI,彻底失去并发读写的性能优势

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 13:36:05