0

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?

Pelle Stenild Coltau
  • 1,268
  • 10
  • 15
  • If you enable the thread sanitizer then it will report a "Swift Access Race" – therefore I assume that it is the same issue as in your previous question [Xcode Incorrectly Reporting Swift Access Race Condition](https://stackoverflow.com/q/54998659/1187415). – Martin R Sep 20 '19 at 10:08
  • Good catch! You are probably right! – Pelle Stenild Coltau Sep 27 '19 at 10:21

0 Answers0