2 Replies
      Latest reply on Apr 14, 2017 2:40 PM by eskimo
      klassobanieras Level 1 Level 1 (0 points)

        So my understanding is that when you pass Swift structs around - Data, Array and so on - Swift won't do a full copy but instead use references, and will only allocate a real copy when you try and write through one of these references.

         

        So I'm wondering - given that Swift's collection types are generally not thread-safe, is this copy-on-write behaviour thread-safe?

         

        If I make 10 copies of an array, and then have 10 threads each start writing to their own copy, will Swift handle this gracefully? From a programming-model standpoint, the threads are each working on their own, independent piece of data, but under the covers there are 10 threads all trying to fork the same object which makes me a little unsure.

        • Re: Is copy-on-write thread-safe?
          sshirokov Level 1 Level 1 (0 points)

          That question a bit old but anyway. What I found (by extensive unit testing) is that it is NOT thread safe. I preriodically see "index of range" error some where inside Array's "description" method on one thread while another thread modifies (append) the array. The Thread Sanitizer also catch a race condition quite well. Observing apple/swift source code repository I see that when it comes to CopyOnWrite it is made inside swift without any kind of locks.

           

          BTW, to overcome this problem I started to make full copy of array under "read" lock, so that clients never see original mutable collection.

          Like following:

           

          class MyClass {

             var items: [Int] { return readLock { return self.mutableItems.map { $0 } } }

             func append(new: Int) { writeLock { self.mutableItems.append(new) } }

             private var mutableItems = [Int]()

          }

           

          I know it's not ideal (constant copying of whole array), but at least multithreading clients of myClass can safely enumerate on "myclass.items" while others may do modifications.

           

          And here is problematic code version:

           

          class MyProblematicClass {

             var items: [Int] { return self.mutableItems }   // it doesn't matter whether you use "read" lock here or not

             ...

          }

            • Re: Is copy-on-write thread-safe?
              eskimo Apple Staff Apple Staff (10,285 points)

              What I found (…) is that it is NOT thread safe.

              Correct.  I’m sorry you had to find this out the hard way )-:  By way of explanation, check out the documentation for isKnownUniquelyReferenced(_:) reference, which shows a typical COW method behaving like this:

              mutating func update(withValue value: T) {
                  if !isKnownUniquelyReferenced(&myStorage) {
                      myStorage = self.copiedStorage()
                  }
                  myStorage.update(withValue: value)
              }
              

              The race condition here is pretty clear.

              Share and Enjoy

              Quinn “The Eskimo!”
              Apple Developer Relations, Developer Technical Support, Core OS/Hardware
              let myEmail = "eskimo" + "1" + "@apple.com"