Hi Jens, In the SynchronizedArray class, I use a lock to perform mutating operations on the array. However, my questions concern the case where an array is exposed as a public property of a thread-safe class, like this:
public class MyClass { private var _myArray: Array<Int> = [] private var _lock = NSLock() public var myArray: Array<Int> { _lock.lock() defer { _lock.unlock() } return _myArray } public func doSomethingThatMutatesArray() { _lock.lock() _myArray.append(1) _lock.unlock() } } Arrays are implemented as structs in Swift. This is a value type, but because Array<T> implements copy-on-write, there is an issue if you do something like this from multiple threads: let myClass = MyClass() func callFromMultipleThreads() { let arrayCopy = myClass.myArray arrayCopy.append(2) // race condition here } This is quite problematic, because the user of MyClass shouldn’t have to worry about side-effects when using a copy of the value from myArray. > On Dec 5, 2017, at 8:22 PM, Jens Alfke <j...@mooseyard.com> wrote: > > > >> On Dec 5, 2017, at 6:24 AM, Michel Fortin via swift-users >> <swift-users@swift.org <mailto:swift-users@swift.org>> wrote: >> >> The array *storage* is copy on write. The array variable (which essentially >> contains a pointer to the storage) is not copy on write. If you refer to the >> same array variable from multiple threads, you have a race. Rather, use a >> different copy of the variable to each thread. Copied variables will share >> the same storage but will make a copy of the storage when writing to it. > > I think you’ve misunderstood. The race condition Romain is referring to is > when the two threads both access the shared storage, through separate array > variables. > > Romain: > From the thread sanitizer warnings, it sounds like the implementation of > Array is not using synchronization around its call(s) to > isKnownUniquelyReferenced … which would mean the class is not thread-safe. > > It’s pretty common for the regular (mutable) collection classes supplied by a > framework to be non-thread-safe; for example consider Foundation and Java. > The reason is that the overhead of taking a lock every time you access an > array element is pretty high. Generally it’s preferable to use > larger-granularity locks, i.e. grab an external lock before performing a > number of array operations. > > —Jens
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users