线程安全问题排查
问题
多线程访问共享数据导致偶发 Crash 或数据异常,如何排查?
答案
排查工具
| 工具 | 用途 |
|---|---|
| Thread Sanitizer (TSan) | 编译期检测数据竞争 |
| Xcode Thread Checker | 检测非主线程操作 UI |
| Crash 堆栈 | 多线程同时出现在同一数据结构 |
开启 TSan
Xcode → Scheme → Diagnostics → Thread Sanitizer ✅
常见场景及修复
// ❌ 多线程同时读写数组
var items: [String] = []
// Thread A: items.append("a")
// Thread B: let count = items.count // 💥 Crash
// ✅ 方案一:串行队列
private let queue = DispatchQueue(label: "com.app.items")
func addItem(_ item: String) {
queue.sync { items.append(item) }
}
func getItems() -> [String] {
queue.sync { items }
}
// ✅ 方案二:读写锁(并发读,互斥写)
private let queue = DispatchQueue(label: "com.app.items", attributes: .concurrent)
func addItem(_ item: String) {
queue.async(flags: .barrier) { self.items.append(item) }
}
func getItems() -> [String] {
queue.sync { items }
}
// ✅ 方案三:Swift Actor (推荐)
actor ItemStore {
private var items: [String] = []
func add(_ item: String) { items.append(item) }
func getAll() -> [String] { items }
}
常见面试问题
Q1: Actor 和传统锁的区别?
答案:Actor 是 Swift 语言级的并发隔离机制。所有访问自动转为 await,编译器保证同一时间只有一个任务访问 Actor 内部状态,无需手动加锁。消除了忘记加锁、死锁等问题。