我相信XCode在我的SynchronizedDictionary
中错误地报告了Swift Access Race-是吗?
我的SynchronizedDictionary
看起来像这样:
public struct SynchronizedDictionary<K: Hashable, V> {
private var dictionary = [K: V]()
private let queue = DispatchQueue(
label: "SynchronizedDictionary",
qos: DispatchQoS.userInitiated,
attributes: [DispatchQueue.Attributes.concurrent]
)
public subscript(key: K) -> V? {
get {
return queue.sync {
return self.dictionary[key]
}
}
mutating set {
queue.sync(flags: .barrier) {
self.dictionary[key] = newValue
}
}
}
}
以下测试代码将触发“快速访问竞赛”问题(为该方案打开线程清理器时):
var syncDict = SynchronizedDictionary<String, String>()
let setExpectation = XCTestExpectation(description: "set_expectation")
let getExpectation = XCTestExpectation(description: "get_expectation")
let queue = DispatchQueue(label: "SyncDictTest", qos: .background, attributes: [.concurrent])
queue.async {
for i in 0...100 {
syncDict["\(i)"] = "\(i)"
}
setExpectation.fulfill()
}
queue.async {
for i in 0...100 {
_ = syncDict["\(i)"]
}
getExpectation.fulfill()
}
self.wait(for: [setExpectation, getExpectation], timeout: 30)
Swift Race Access看起来像这样:
我真的没想到这里会有访问竞争的情况,因为
SynchronizedDictionary
应该处理并发。我可以通过在测试中将获取和设置包装在与
SynchronizedDictionary
的实际实现类似的DispatchQueue中来解决此问题:let accessQueue = DispatchQueue(
label: "AccessQueue",
qos: DispatchQoS.userInitiated,
attributes: [DispatchQueue.Attributes.concurrent]
)
var syncDict = SynchronizedDictionary<String, String>()
let setExpectation = XCTestExpectation(description: "set_expectation")
let getExpectation = XCTestExpectation(description: "get_expectation")
let queue = DispatchQueue(label: "SyncDictTest", qos: .background, attributes: [.concurrent])
queue.async {
for i in 0...100 {
accessQueue.sync(flags: .barrier) {
syncDict["\(i)"] = "\(i)"
}
}
setExpectation.fulfill()
}
queue.async {
for i in 0...100 {
accessQueue.sync {
_ = syncDict["\(i)"]
}
}
getExpectation.fulfill()
}
self.wait(for: [setExpectation, getExpectation], timeout: 30)
...但是这已经在
SynchronizedDictionary
内部发生了-那么Xcode为什么报告访问争用情况? -Xcode出错了,还是我错过了什么? 最佳答案
线程清理程序将Swift access race报告给
var syncDict = SynchronizedDictionary<String, String>()
结构,因为(通过下标设置器)在
syncDict["\(i)"] = "\(i)"
从一个线程访问,并在以下位置对同一结构(通过下标getter)进行只读访问
_ = syncDict["\(i)"]
从另一个线程,没有同步。
这与对
private var dictionary
属性的访问冲突或与下标方法内部发生的操作完全无关。如果将结构简化为以下内容,则将获得相同的“快速访问竞赛”public struct SynchronizedDictionary<K: Hashable, V> {
private let dummy = 1
public subscript(key: String) -> String {
get {
return key
}
set {
}
}
}
因此,这是来自线程清理程序的正确报告,而不是错误。
一个可能的解决方案是定义一个类:
public class SynchronizedDictionary<K: Hashable, V> { ... }
这是一种引用类型,下标设置程序不再更改
syncDict
变量(现在是实际对象存储中的“指针”)。有了这一更改,您的代码便可以正常运行。关于swift - Xcode错误地报告Swift Access竞争情况,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58025624/