【发布时间】:2018-06-10 14:12:50
【问题描述】:
我有 Set<CostumObject> 类型的实例,我想使用 NSKeyedArchiver 归档这些实例。
假设customObject1: CostumObject 和customObject2: CostumObject 在某处被实例化。
如果我使用以下语句:
let setOfCostomObjects: Set<CostumObject> = [customObject1, customObject2]
let data = NSKeyedArchiver.archivedData(withRootObject: setOfCostomObjects)
NSKeyedArchiver 按顺序归档两个自定义对象,其中它们的属性被递归归档。
这不是线程安全的,因为另一个线程可以在归档期间同时改变自定义对象及其属性。
我认为我可以线程安全地归档自定义对象的每个属性,以便允许并发获取,但只允许一个集合,方法是使用带有障碍的并发队列,例如:
private let concurrentPropertyAccessQueue = DispatchQueue(label: "concurrentPropertyAccessQueue", attributes: .concurrent)
…
private var safeProperty = CostumProperty.init()
public private(set) var property: CostumProperty {
get {
var result = CostumProperty.init()
concurrentPropertyAccessQueue.sync { result = safeProperty } // sync, because result is returned
return result
} // get
set { concurrentPropertyAccessQueue.async(flags: .barrier) { safeProperty = newValue } // executes locked after all gets
} // set
}
…
public func threadSafeArchiveOfProperty() -> Data {
var data = Data.init()
concurrentPropertyAccessQueue.sync { // sync, because result is returned
data = NSKeyedArchiver.archivedData(withRootObject: self.safeProperty)
}
return data
}
我想我也可以用类似的方式对整个自定义对象进行线程安全归档:
private let concurrentObjectAccessQueue = DispatchQueue(label: "concurrentObjectAccessQueue", attributes: .concurrent)
…
public func encode(with aCoder: NSCoder) {
concurrentObjectAccessQueue.async(execute: {
aCoder.encode(self.property forKey: "property")
…
})
}
问题仍然是,如何对自定义对象集进行线程安全存档。
这将要求在归档期间锁定对集合元素的写访问。
这样做的一种方法可能是定义一个全局并发队列:
public let globalConcurrentAccessQueue = DispatchQueue(label: "globalConcurrentAccessQueue", attributes: .concurrent)
要在归档过程中锁定集合及其所有元素,可以编写一个对Set 类型的扩展,它定义了一个func threadSafeArchiveOfSet(),如上所述。
然后,此函数将覆盖 Set 的 encode(with aCoder: NSCoder),从而锁定 globalConcurrentAccessQueue。
这是正确的方法吗?
我认为这是一个标准问题,应该有一个标准的解决方案。
【问题讨论】:
-
@Rob 感谢您的快速回复。我必须理解他们,并且会回来。
-
@Rob 关于属性级同步:你是完全正确的:为了保持对象整体一致,变异自身或它的任何属性必须在对象级别同步,属性级同步是过时的。关于异步编码:你又是对的:调用者 NSKeyedArchiver 可能假设编码是一个顺序过程,因为所有单独的归档结果都将组合到一个最终数据对象中。
-
@Rob 关于同步模式的简化:有趣!我不知道这个。您的建议有效,但我在 docs 中找不到它。同步不应该有返回值吗?
-
@Rob 再次感谢您的 cmets。也许你可以制定一个答案,以便我可以结束这个问题。
标签: swift multithreading collections thread-safety archiving