Pel*_*tau 5 xcode multithreading race-condition swift ios-multithreading
我相信 XCode 错误地报告了我的 Swift Access Race SynchronizedDictionary- 或者是这样?
我的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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
以下测试代码将触发“Swift Access Race”问题(当为该方案打开Thread Sanitizer时):
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)
Run Code Online (Sandbox Code Playgroud)
Swift Race Access 如下所示:
我真的没想到这里会出现访问竞争条件,因为应该SynchronizedDictionary处理并发性。
我可以通过在测试中将获取和设置包装在 DispatchQueue 中来解决该问题,类似于以下的实际实现SynchronizedDictionary:
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)
Run Code Online (Sandbox Code Playgroud)
...但这已经发生在SynchronizedDictionary- 那么为什么 Xcode 报告访问竞争条件?- 是 Xcode 有问题,还是我遗漏了什么?
线程清理程序报告Swift 访问竞争
\n\nvar syncDict = SynchronizedDictionary<String, String>()\nRun Code Online (Sandbox Code Playgroud)\n\n结构,因为有一个变异访问(通过下标设置器)
\n\nsyncDict["\\(i)"] = "\\(i)"\nRun Code Online (Sandbox Code Playgroud)\n\n从一个线程,以及对同一结构的只读访问(通过下标 getter)
\n\n_ = syncDict["\\(i)"]\nRun Code Online (Sandbox Code Playgroud)\n\n来自不同的线程,没有同步。
\n\n这与对属性的冲突访问无关private var dictionary,也与下标方法内发生的情况无关。如果将结构简化为,您将获得相同的 \xe2\x80\x9cSwift access race\xe2\x80\x9d
public struct SynchronizedDictionary<K: Hashable, V> {\n private let dummy = 1\n\n public subscript(key: String) -> String {\n get {\n return key\n }\n set {\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n所以这是一个正确的报告,而不是错误。
\n\n一个可能的解决方案是定义一个类:
\n\npublic class SynchronizedDictionary<K: Hashable, V> { ... }\nRun Code Online (Sandbox Code Playgroud)\n\n这是一个引用类型,下标设置器不再改变syncDict(现在是 \xe2\x80\x9cpointer\xe2\x80\x9d 到实际对象存储中)。进行此更改后,您的代码将不会出现错误。
| 归档时间: |
|
| 查看次数: |
994 次 |
| 最近记录: |