<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">Hi Jens,<div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class="">public class MyClass {</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>private var _myArray: Array<Int> = []</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>private var _lock = NSLock()</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>public var myArray: Array<Int> {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>_lock.lock()</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>defer { _lock.unlock() }</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>return _myArray</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>public func doSomethingThatMutatesArray() {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>_lock.lock()</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>_myArray.append(1)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>_lock.unlock()</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class="">}</div><div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class="">let myClass = MyClass()</div><div class=""><br class=""></div><div class="">func callFromMultipleThreads() {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>let arrayCopy = myClass.myArray</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>arrayCopy.append(2) // race condition here</div><div class="">}</div><div class=""><br class=""></div><div class="">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.<br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Dec 5, 2017, at 8:22 PM, Jens Alfke <<a href="mailto:jens@mooseyard.com" class="">jens@mooseyard.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Dec 5, 2017, at 6:24 AM, Michel Fortin via swift-users <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><span style="font-family: Alegreya-Regular; font-size: 15px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">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.</span><br class="Apple-interchange-newline"></div></blockquote></div><br class=""><div class="">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.</div><div class=""><br class=""></div><div class="">Romain:</div><div class="">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.</div><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class="">—Jens</div></div></div></blockquote></div><br class=""></div></body></html>