Я считаю, что 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
}
}
}
}
Следующий тестовый код вызовет проблему «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)
Доступ к Swift Race выглядит следующим образом:
Я действительно не ожидал, что здесь будет состояние гонки за доступ, потому что 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)
... но это уже происходит внутри SynchronizedDictionary
- так почему же Xcode сообщает о состоянии гонки за доступ? - виноват ли Xcode или я что-то упустил?