【发布时间】:2021-04-14 20:03:04
【问题描述】:
我在 Swift 中为我的 Swift 类创建了一个“锁”和一个使用该锁的 Atomic 属性包装器,因为 Swift 缺少 ObjC 的 atomic 属性属性。
当我在启用线程清理器的情况下运行测试时,它总是会在使用我的 Atomic 属性包装器的属性上捕获数据竞争。
唯一有效的是将属性包装器的声明更改为类而不是结构,这里的主要问题是:为什么有效!
我在属性包装器中添加了prints 并锁定inits 以跟踪创建的对象数量,与结构/类相同,尝试在另一个项目中重现问题,也没有工作.但我会添加与问题相似的文件,并让我知道为什么会起作用的任何猜测。
锁定
public class SwiftLock {
init() { }
public func sync<R>(execute: () throws -> R) rethrows -> R {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
return try execute()
}
}
原子属性包装器
@propertyWrapper struct Atomic<Value> {
let lock: SwiftLock
var value: Value
init(wrappedValue: Value, lock: SwiftLock=SwiftLock()) {
self.value = wrappedValue
self.lock = lock
}
var wrappedValue: Value {
get {
lock.sync { value }
}
set {
lock.sync { value = newValue }
}
}
}
模型(数据竞争应该发生在 publicVariable2 属性上)
class Model {
@Atomic var publicVariable: TimeInterval = 0
@Atomic var publicVariable2: TimeInterval = 0
var sessionDuration: TimeInterval {
min(0, publicVariable - publicVariable2)
}
}
更新 1: 完整的 Xcode 项目:https://drive.google.com/file/d/1IfAsOdHKOqfuOp-pSlP75FLF32iVraru/view?usp=sharing
【问题讨论】:
-
感谢您提供所有代码,但您能提供一个minimal reproducible example 吗?为了测试,我们需要做什么?
-
我在问题中添加了项目的链接。它包括问题中提到的代码示例 + 带有模拟场景的测试的测试目标。再次值得一提的是,我没有设法重现这个项目的问题,不幸的是我无法分享原始代码。
-
我想这是因为 objc_sync_* 方法要求它们的参数具有标识。结构没有那个,只有类。
-
@Clashsoft 但锁中的
self指的是SwiftLock而不是Atomic -
我相信this 的帖子——标题为“objc_sync_enter / objc_sync_exit not working with DISPATCH_QUEUE_PRIORITY_LOW”——足以回答这个问题。看Sir Wellington在讨论中的回答。基本上,问题的出现是因为 Swift 结构是值类型。在同一个讨论中还建议使用 GCD 而不是
objc_sync_enter,因为后者是旧的并且非常低级
标签: ios swift property-wrapper ios-multithreading swift-structs