I have the following SynchronizedDictionary
:
public struct SynchronizedDictionary<K: Hashable, V> {
private var dictionary = [K: V]()
private let queue = DispatchQueue(
label: "SynchronizedDictionary",
attributes: [DispatchQueue.Attributes.concurrent]
)
public subscript(key: K) -> V? {
get {
return queue.sync {
return self.dictionary[key]
}
}
mutating set {
queue.sync(flags: DispatchWorkItemFlags.barrier) {
self.dictionary[key] = newValue
}
}
}
mutating func removeAll() {
queue.sync(flags: DispatchWorkItemFlags.barrier) {
self.dictionary.removeAll()
}
}
}
I have the following code, that is designed to test the concurrency of SynchronizedDictionary
. The code will concurrently make read and writes to the dictionary (twice as many reads as writes).
let list = ["1", "2", "3", "4", "5", "6", "7", "8"]
var dict = SynchronizedDictionary<String, String>()
let queue = DispatchQueue.init(label: "test", attributes: .concurrent)
for value in 1...1000 {
let expectation = self.expectation(description: value.description)
queue.async {
let element = list.randomElement()!
if [1, 2, 3].randomElement()! == 1 {
print("writing \(element)")
dict[element] = UUID().uuidString
} else {
print("reading \(element)")
_ = dict[element]
}
expectation.fulfill()
}
}
self.waitForExpectations(timeout: 10, handler: nil)
My problem is that my test crashes with the following stack trace:
...
writing 3
reading 5
reading 2
writing 4
reading 1
2019-09-20 11:13:08.836133+0200 TestApp[39907:2053064] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSTaggedPointerString objectForKey:]: unrecognized selector sent to instance 0x8000000000000000'
*** First throw call stack:
(
0 CoreFoundation 0x000000010b7ff29b __exceptionPreprocess + 331
1 libobjc.A.dylib 0x0000000109e43735 objc_exception_throw + 48
2 CoreFoundation 0x000000010b81dfa4 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 CoreFoundation 0x000000010b803fb6 ___forwarding___ + 1446
4 CoreFoundation 0x000000010b805e88 _CF_forwarding_prep_0 + 120
5 libswiftCore.dylib 0x000000010a81074c $sSD8_VariantVyq_Sgxcig + 140
6 libswiftCore.dylib 0x000000010aa3c599 $sSDyq_Sgxcig + 9
7 MyApp 0x00000001216abd1e $s8MyApp22SynchronizedDictionaryVyq_SgxcigADyXEfU_ + 206
8 MyApp 0x00000001216abdca $s8MyApp22SynchronizedDictionaryVyq_SgxcigADyXEfU_TA + 58
9 libswiftDispatch.dylib 0x000000010ae53941 $sxs5Error_pIgrzo_xsAA_pIegrzo_lTRTA + 17
10 libswiftDispatch.dylib 0x000000010ae4cec2 $sSo17OS_dispatch_queueC8DispatchE11_syncHelper33_F417D752D2C4E9330E1C700411CE0C6ALL2fn7execute6rescuexyyyXEXE_xyKXExs5Error_pKXEtKlFyxyKcXEfU_yyXEfU_ + 82
11 libswiftDispatch.dylib 0x000000010ae539bd $sSo17OS_dispatch_queueC8DispatchE11_syncHelper33_F417D752D2C4E9330E1C700411CE0C6ALL2fn5flags7execute6rescuexyAC0D8WorkItemCXE_AC0dtU5FlagsVxyKXExs5Error_pKXEtKlFyyXEfU_TATm + 29
12 libswiftDispatch.dylib 0x000000010ae53990 $sSo17OS_dispatch_queueC8DispatchE11_syncHelper33_F417D752D2C4E9330E1C700411CE0C6ALL2fn7execute6rescuexyyyXEXE_xyKXExs5Error_pKXEtKlFyxyKcXEfU_yyXEfU_TA + 16
13 libswiftDispatch.dylib 0x000000010ae53741 $sIg_Ieg_TRTA + 17
14 libswiftDispatch.dylib 0x000000010ae54a19 $sIg_Ieg_TRTA.139 + 9
15 libswiftDispatch.dylib 0x000000010ae46e5e $sIeg_IyB_TR + 14
16 libdispatch.dylib 0x000000010cc13587 _dispatch_client_callout + 8
17 libdispatch.dylib 0x000000010cc20366 _dispatch_sync_invoke_and_complete_recurse + 97
18 libdispatch.dylib 0x000000010cc1fde5 _dispatch_sync_f_slow + 225
19 libswiftDispatch.dylib 0x000000010ae4d478 $sSo17OS_dispatch_queueC4sync7executeyyyXE_tFTO + 152
20 libswiftDispatch.dylib 0x000000010ae51510 $sSo17OS_dispatch_queueC4sync7executeyyyXE_tFTOTA + 16
21 libswiftDispatch.dylib 0x000000010ae4cd73 $sSo17OS_dispatch_queueC8DispatchE11_syncHelper33_F417D752D2C4E9330E1C700411CE0C6ALL2fn7execute6rescuexyyyXEXE_xyKXExs5Error_pKXEtKlF + 259
22 libswiftDispatch.dylib 0x000000010ae4d3af $sSo17OS_dispatch_queueC8DispatchE4sync7executexxyKXE_tKlF + 143
23 MyApp 0x00000001216abbf8 $s8MyApp22SynchronizedDictionaryVyq_Sgxcig + 376
24 MyAppTests 0x0000000120733ace $s13MyAppTests26SynchronizedDictionarySpecC4specyyFyyXEfU_yyXEfU_yycfU_yycfU_ + 2286
25 MyAppTests 0x0000000120733f95 $s13MyAppTests26SynchronizedDictionarySpecC4specyyFyyXEfU_yyXEfU_yycfU_yycfU_TA + 21
26 MyAppTests 0x0000000120733bbd $sIeg_IeyB_TR + 45
27 libdispatch.dylib 0x000000010cc1251d _dispatch_call_block_and_release + 12
28 libdispatch.dylib 0x000000010cc13587 _dispatch_client_callout + 8
29 libdispatch.dylib 0x000000010cc15fac _dispatch_continuation_pop + 453
30 libdispatch.dylib 0x000000010cc15619 _dispatch_async_redirect_invoke + 827
31 libdispatch.dylib 0x000000010cc224af _dispatch_root_queue_drain + 355
32 libdispatch.dylib 0x000000010cc22d19 _dispatch_worker_thread2 + 97
33 libsystem_pthread.dylib 0x000000010cffb6b3 _pthread_wqthread + 583
34 libsystem_pthread.dylib 0x000000010cffb3fd start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException
If I change the SynchronizedDictionary
to a class, the test runs fine!
Can anyone explain why?