Swift 6编译AsyncStack<>遇数据竞争风险错误:原因及修复
Swift 6下AsyncStack编译错误原因及修复方案
错误原因
Swift 6默认启用了严格并发检查,对跨并发上下文传递的值的安全性要求更高。当你在push方法中调用awaiter.resume(returning: newElement)时,newElement作为外部传入的参数,其所有权不由当前actor完全控制:
- 若
Element是可变引用类型,外部调用者可能在push执行期间同时修改该元素; resume操作会将元素传递到另一个并发上下文(等待popOrWait的任务),这就存在数据竞争的风险,因此编译器触发了报错。
修复方案
方案1:约束Element遵循Sendable协议
给AsyncStack的泛型参数添加Sendable约束,确保存储和传递的元素是可安全跨并发上下文传递的类型(比如值类型、不可变引用类型、显式标记为Sendable的类型):
actor AsyncStack<Element: Sendable> { private var storage = [Element]() private var awaiters = [CheckedContinuation<Element,Error>]() public func push(_ newElement: Element) async -> Void { if !awaiters.isEmpty { let awaiter = awaiters.removeFirst() awaiter.resume(returning: newElement) } else { storage.insert(newElement, at: 0) } } public func popOrWait() async throws -> Element { if let element = storage.popLast() { return element } return try await withCheckedThrowingContinuation { continuation in awaiters.append(continuation) } } }
方案2:显式复制元素(仅适用于值类型)
如果Element是值类型,显式复制元素可以让编译器确认传递的是独立副本,消除竞争风险:
// 在push方法中修改resume调用部分 if !awaiters.isEmpty { let awaiter = awaiters.removeFirst() var copiedElement = newElement // 利用值类型自动复制特性生成独立副本 awaiter.resume(returning: copiedElement) }
注意:此方案仅对值类型有效,引用类型仍需依赖Sendable约束保证安全性。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

