Let's say, there is a variable that I want to make thread safe. One of the most common ways to do this:
var value: A {
get { return queue.sync { self._value } }
set { queue.sync { self._value = newValue } }
}
However, this property is not completely thread safe if we change the value as in the example below:
Class.value += 1
So my question is: Using NSLock on the same principle is also not completely thread safe?
var value: A {
get {
lock.lock()
defer { lock.unlock() }
return self._value
}
set {
lock.lock()
defer { lock.unlock() }
self._value = newValue
}
}
That's interesting, I'm learning about this for the first time.
The issue in the first bit of code, is that:
object.value += 1has the same semantics as
object.value = object.value + 1which we can further expand to:
Expanding it so makes it clear that the synchronization of the getter and setter work fine, but they're not synchronized as a whole. A context switch in the middle of the code above could cause
_valueto be mutated by another thread, withoutnewValuereflecting the change.Using a lock would have the exact same problem. It would expand to:
You can see this for yourself by instrumenting your code with some logging statements, which show that the mutation isn't fully covered by the lock: