Swift 4 GCD线程安全:除竞态条件外是否存在其他线程问题?
多线程调用
changeSomeResources()的潜在线程问题分析 先梳理下你的核心代码和调用逻辑:
资源控制函数
var resource: Int? func changeSomeResources() { resource = 1 // rewriting keychain parameters // working with UIApplication.shared }
多线程调用方式
DispatchQueue.global(qos: .userInitiated).async { changeSomeResources() } DispatchQueue.global(qos: .userInitiated).async { changeSomeResources() }
除了你提到的resource变量的竞态条件之外,这个场景还存在几个容易被忽略的线程风险:
1. UI线程违规操作导致的崩溃/异常
你在函数里提到了working with UIApplication.shared——UIKit框架(包括UIApplication的多数操作)严格要求所有UI相关的调用必须在主线程执行。如果你的函数里对UIApplication的操作(比如修改应用状态、访问UI相关属性)直接在全局后台队列执行,会触发不可预测的行为:轻则UI状态异常、控件不更新,重则直接抛出崩溃(比如常见的EXC_BAD_ACCESS或UIKit断言失败)。
2. Keychain操作的线程安全隐患
虽然苹果文档提到部分Keychain API是线程安全的,但当多个后台线程同时写入同一个Keychain条目时,依然存在风险:
- 可能出现写入冲突,导致最终Keychain中的数据与预期不符;
- 极端情况下可能出现操作失败(返回错误码),甚至数据丢失;
- 多线程并发读写Keychain还可能引发性能瓶颈,因为Keychain本身涉及系统级的锁机制,频繁并发调用会增加线程等待时间。
3. 无保证的执行顺序引发逻辑错误
全局队列是并发队列,两个changeSomeResources()任务的执行顺序、完成时间都是不确定的。如果你的业务逻辑隐含了“第一个任务完成后再执行第二个”的依赖(比如第二个任务需要基于第一个任务修改后的Keychain状态),这种并发调用就会导致逻辑混乱,出现不符合预期的业务结果。
4. 优先级反转风险
你使用了.userInitiated的QoS(服务质量)级别,但如果多个线程同时竞争同一资源(比如resource变量或Keychain),可能会出现优先级反转:高优先级的线程被低优先级的线程阻塞,导致应用的响应速度下降,影响用户体验。
简单的修复建议
- UI操作强制切主线程:把函数里涉及
UIApplication.shared的代码用主线程包裹:DispatchQueue.main.async { // 这里放UIApplication相关操作 } - 共享资源加同步机制:给
resource变量和Keychain操作加串行队列或锁,保证原子性:// 创建专用串行队列处理资源操作 private let resourceQueue = DispatchQueue(label: "com.yourapp.resourceQueue") func changeSomeResources() { resourceQueue.sync { resource = 1 // 这里放Keychain修改操作 } // UI操作单独切主线程 DispatchQueue.main.async { // 处理UIApplication相关逻辑 } } - 控制任务执行顺序:如果需要保证任务的执行顺序,不要用并发队列异步调用,改用串行队列或者让第一个任务完成后再触发第二个。
内容的提问来源于stack exchange,提问作者Sergey Polozov
相关产品推荐
相关产品推荐

