跳到主要内容

常见并发问题

问题

iOS 开发中常见的并发问题有哪些?如何预防和排查?

答案

1. 死锁

// 经典死锁:主队列 sync
DispatchQueue.main.sync { // ❌ 主线程等自己执行完 → 死锁
print("永远不执行")
}

// 串行队列嵌套 sync
let queue = DispatchQueue(label: "serial")
queue.async {
queue.sync { // ❌ 外层任务等内层完成,内层等外层让出 → 死锁
print("永远不执行")
}
}

2. 数据竞争

// ❌ 多线程同时读写
var count = 0
DispatchQueue.concurrentPerform(iterations: 1000) { _ in
count += 1 // 数据竞争!结果 < 1000
}

// ✅ 使用锁或 Actor
actor Counter {
var count = 0
func increment() { count += 1 }
}

3. 线程爆炸

// ❌ 大量 sync 调用阻塞线程 → GCD 持续创建新线程
for i in 0..<1000 {
DispatchQueue.global().async {
semaphore.wait() // 如果信号量长时间等待,线程被阻塞
// ...
semaphore.signal()
}
}

// ✅ 使用 Swift Concurrency(不阻塞线程)
await withTaskGroup(of: Void.self) { group in
for i in 0..<1000 {
group.addTask { await process(i) }
}
}

4. 优先级反转

高优先级任务等待低优先级任务释放资源,而低优先级任务因 CPU 时间不足迟迟无法完成。

  • os_unfair_lock 替代 OSSpinLock(自旋锁)
  • GCD 的 QoS 自动处理优先级提升

排查工具

工具用途
Thread Sanitizer(TSan)编译时检测数据竞争
Instruments - Thread States线程状态分析
Xcode Runtime Issue运行时并发警告
Swift 6 strict concurrency编译器静态分析
Thread Sanitizer
Product → Scheme → Edit Scheme → Diagnostics → Thread Sanitizer ✅

TSan 会在运行时检测并报告数据竞争,开发和测试阶段必开。


常见面试问题

Q1: 如何排查死锁?

答案

  1. Debug 时暂停运行,查看 Thread 列表
  2. 多个线程卡在同一个 syncwait → 死锁
  3. 使用 Instruments 的 System Trace 分析线程阻塞情况
  4. 遵循规则:不要在串行队列中对自身 sync

Q2: Swift 6 的 strict concurrency 解决什么问题?

答案:Swift 6 默认开启严格并发检查,编译器会在编译时发现:

  • 跨并发域传递非 Sendable 类型
  • 非隔离上下文访问 actor 的属性
  • 闭包捕获可变状态的并发风险

这让大部分并发 Bug 在编译时就被捕获,而非运行时崩溃。

相关链接