如何解决原子属性包装器仅在声明为类时才有效,而不是 struct
我在 Swift 中创建了一个“锁”,并为我的 Swift 类创建了一个使用该锁的 Atomic 属性包装器,因为 Swift 缺少 ObjC 的 atomic
属性属性。
当我在启用线程清理器的情况下运行我的测试时,它总是捕获使用我的 Atomic 属性包装器的属性上的数据竞争。
唯一有效的是将属性包装器的声明更改为类而不是结构体,这里的主要问题是:为什么有效!
我在属性包装器中添加了 print
并锁定 init
以跟踪创建的对象数量,结构/类也是如此,尝试在另一个项目中重现该问题,但没有也不行。但是我会添加与问题类似的文件,并让我知道关于为什么会起作用的任何猜测。
锁定
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
解决方法
这个问题在这个 PR 中得到了回答:https://github.com/apple/swift-evolution/pull/1387
我认为这些台词真正解释了它?
在Swift的正式内存访问模型中,值类型上的方法被认为是访问整个值,因此调用wrappedValue getter正式读取整个存储的包装器,而调用wrappedValue的setter正式修改整个存储的包装器。
包装器的值将在调用之前加载
wrappedValue.getter
并在调用后写回
wrappedValue.setter
。因此,包装器内的同步
无法提供对其自身值的原子访问。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。