YERIM LEE
YERIM LEE

Reputation: 23

Is value type really safe in multple threads?

Apple said "If you use Value type, you can safely pass copies of values across threads without synchronization.". But I saw concurrency crash at variance with the apple guide recently.

I saw https://developer.apple.com/swift/blog/?id=10 and Apple's guide that said "value type is safe in multithreads" so I thought "Value type is atomic!" but recently I saw concurrency crash in code below.

class ClassB: NSObject {

   func readSomeValue() {
      print(classA.someValue)
   }

   let classA = ClassA()

}

class ClassA: NSObject {

  private(set) var someValue: StructA? {
    didSet{
      if oldValue != self.someValue { self.someFunction(self.someValue) }
    }
  }

  private func modifySomeValue(_ newValue: StructA) {
    self.someValue = newValue
  }
}

struct StructA {
  var a: Double
  var b: String?
}

concurrency crash is occured when execute readSomeValue() in thread1 and execute modifySomeValue() in thread2. Why does concurrency crash happen? Is Value type not safe in multithreads?

Upvotes: 2

Views: 118

Answers (1)

Rob
Rob

Reputation: 437792

A couple of observations:

  1. That blog entry says:

    Importantly, you can safely pass copies of values across threads without synchronization.

    The operative word here is “copies”.

    But in your example, you’re not passing copies of a value-type object to the different threads. You’re sharing single instance of reference-type object, a class, between the threads. Sure, your reference-type has a value-type property, but that doesn’t alter the fact that you’re sharing a single instance of your reference-type object instance across threads. You will have to manually synchronize your interaction with that object and its properties in order to enjoy thread-safety.

  2. There’s an argument to be made that many discussions mislead readers into thinking that Swift value-types always enjoy copy (or copy-on-write) semantics, and therefore always enjoy this thread safety feature. But you have to be careful, because there are several examples where you don’t get copy semantics. Your example of having a value-type property within a reference-type object is one example.

    Another example is when you fail to use closure “capture lists”. For example, the following is not thread-safe as it is using the same value-type instance across multiple threads:

    var object = StructA(a: 42, b: "foo")
    DispatchQueue.global().async {
        print(object)
    }
    object.b = "bar"
    

    But by adding the capture list, the global queue will have its own copy of the object, restoring this thread-safety interaction across threads because each thread has its own copy of the object in question:

    var object = StructA(a: 42, b: "foo")
    DispatchQueue.global().async { [object] in
        print(object)
    }
    object.b = "bar"
    
  3. Yes, you can write thread-safe code if you (a) use value types; and (b) pass copies of these value types around. But this has nothing to do with atomicity. Bottom line, Swift variables are not atomic.

Upvotes: 2

Related Questions