<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=""><div class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div class="">Ah, it's a Swift bug in the SynchronizedArray / MyClass cases</div></div></blockquote><br class=""></div><div class="">If I remove the intermediate copy in the myArray getter, should it — without Swift bug — also return a unique copy?</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="color: #ba2da2" class="">public</span> <span style="color: #ba2da2" class="">var</span> myArray: <span style="color: #703daa" class="">Array</span>&lt;<span style="color: #703daa" class="">Int</span>&gt; {</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; lock.lock()</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; <span style="color: #ba2da2" class="">defer</span> { lock.unlock() }</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; _myArray</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">}</div></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><br class=""></div>By the way, here is a simpler sample code where TSan also detects a race condition:<br class=""><br class="">// Code sample A<div class=""><br class="">var&nbsp;array: [Int] = [1,&nbsp;2,&nbsp;3]<br class=""><br class="">let&nbsp;iterations =&nbsp;1_000_000<br class=""><br class="">var&nbsp;copy1 = array<br class="">q1.async&nbsp;{<br class="">&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;copy1.append(i)<br class="">&nbsp; &nbsp;&nbsp;}<br class="">}<br class=""><br class="">var&nbsp;copy2 = array<br class="">q2.async&nbsp;{<br class="">&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;copy2.append(i)<br class="">&nbsp; &nbsp;&nbsp;}<br class="">}<br class=""><br class="">var&nbsp;copy3 = array<br class="">q3.async&nbsp;{<br class="">&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;copy3.append(i)<br class="">&nbsp; &nbsp;&nbsp;}<br class="">}<br class=""><br class="">for&nbsp;i&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp;&nbsp;array.append(i)<br class="">}<br class=""><br class="">q1.sync&nbsp;{}<br class="">q2.sync&nbsp;{}<br class="">q3.sync&nbsp;{}<br class="">NSLog("done")<br class=""><br class="">I can avoid the race condition to occur by using a capture list:<br class=""><br class="">// Code sample B<div class=""><br class="">var&nbsp;array: [Int] = [1, 2,&nbsp;3]<div class=""><br class="">let&nbsp;iterations =&nbsp;1_000_000<br class=""><br class="">q1.async&nbsp;{ [array]&nbsp;in<br class="">&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;var&nbsp;copy = array<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;copy.append(i)<br class="">&nbsp; &nbsp;&nbsp;}<br class="">}<br class=""><br class="">q2.async&nbsp;{ [array]&nbsp;in<br class="">&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;var&nbsp;copy = array<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;copy.append(i)<br class="">&nbsp; &nbsp;&nbsp;}<br class="">}<br class=""><br class="">q3.async&nbsp;{ [array]&nbsp;in<br class="">&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;var&nbsp;copy = array<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;copy.append(i)<br class="">&nbsp; &nbsp;&nbsp;}<br class="">}<br class=""><br class="">for&nbsp;i&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp;&nbsp;array.append(i)<br class="">}<div class=""><br class=""></div><div class="">q1.sync&nbsp;{}<br class="">q2.sync&nbsp;{}<br class="">q3.sync&nbsp;{}<br class="">NSLog("done")<br class=""><br class="">or by using a constant copy, which, if I’m not wrong, should behave the same way than the capture list:<div class=""><br class=""></div><div class="">// Code sample C</div><div class=""><br class=""></div><div class="">var&nbsp;array: [Int] = [1,&nbsp;2,&nbsp;3]<br class=""><br class="">let&nbsp;iterations =&nbsp;1_000_000<br class=""><br class="">let&nbsp;copy1 = array<br class="">q1.async {<br class="">&nbsp; &nbsp;&nbsp;var&nbsp;copy1 = copy1<br class="">&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;copy1.append(i)<br class="">&nbsp; &nbsp;&nbsp;}<br class="">}<br class=""><br class=""><br class="">let&nbsp;copy2 = array<br class="">q2.async {<br class="">&nbsp; &nbsp;&nbsp;var&nbsp;copy2 = copy2<br class="">&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;copy2.append(i)<br class="">&nbsp; &nbsp;&nbsp;}<br class="">}<br class=""><br class="">let&nbsp;copy3 = array<br class="">q3.async {<br class="">&nbsp; &nbsp;&nbsp;var&nbsp;copy3 = copy3<br class="">&nbsp; &nbsp;&nbsp;for&nbsp;i&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;copy3.append(i)<br class="">&nbsp; &nbsp;&nbsp;}<br class="">}<br class=""><br class="">for&nbsp;_&nbsp;in&nbsp;0..&lt;iterations {<br class="">&nbsp; &nbsp;&nbsp;array.append(array.count)<br class="">}<br class=""><br class="">q1.sync {}<br class="">q2.sync {}<br class="">q3.sync {}<br class="">NSLog("done")<br class=""><div class=""><br class=""></div><div class="">Do you also think the data race in "sample code A" above is a Swift bug?<br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Dec 6, 2017, at 1:04 AM, Jordan Rose &lt;<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>&gt; 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=""><div class="">Ah, it's a Swift bug in the SynchronizedArray / MyClass cases, and your bug in the very first example with the global (since access to the global itself is not synchronized). The case I actually tested myself was with your most recent example ("Yet, data race can occur here").</div><div class=""><br class=""></div><div class="">Jordan</div><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Dec 5, 2017, at 15:53, Romain Jacquinot &lt;<a href="mailto:rjacquinot@me.com" class="">rjacquinot@me.com</a>&gt; 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="">Hi Jordan,<div class=""><br class=""></div><div class="">For which specific code sample(s) do you think it’s a bug? In the previous code samples, are there cases where you think a data race is to be expected?</div><div class=""><br class=""></div><div class="">Thanks.</div><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Dec 6, 2017, at 12:05 AM, Jordan Rose &lt;<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>&gt; 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="">I'm seeing the race too when compiling with -O (and TSan enabled). I'm 95% sure this should be valid Swift code without any further synchronization, so please file a bug at <a href="https://bugs.swift.org/" class="">https://bugs.swift.org</a>. (But I'm only 95% sure because concurrency is hard.)<div class=""><br class=""></div><div class="">Looking at the backtraces, it looks like one thread thinks it has exclusive ownership of the buffer while the other thread is still copying things out of it. <b class="">This is a bug on Swift's side</b>; this code should work. I'm pretty sure this is actually a situation I was just talking about with Michael I from the stdlib team a few days ago, so it's good to have a test case for it.</div><div class=""><br class=""></div><div class=""><div class="">Jordan</div><div class=""><div class=""><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Dec 5, 2017, at 14:23, Romain Jacquinot via swift-users &lt;<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>&gt; 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="">Also, on the official Swift blog (<a href="https://developer.apple.com/swift/blog/?id=10" class="">https://developer.apple.com/swift/blog/?id=10</a>), it is stated that:<div class=""><br class=""></div><div class="">"One of the primary reasons to choose value types over reference types is the ability to more easily reason about your code. If you always get a unique, copied instance, you can trust that no other&nbsp;part of your app is changing the data under the covers. This is especially helpful in multi-threaded environments where a different thread could alter your data out from under you.</div><div class="">[…]</div><div class="">In Swift,&nbsp;Array,&nbsp;String, and&nbsp;Dictionary&nbsp;are all value types. They behave much like a simple&nbsp;int&nbsp;value in C, acting as a unique instance of that data. You don’t need to do anything special —&nbsp;such as making an explicit copy — to prevent other code from modifying that data behind your back. Importantly, you can safely pass copies of values across threads without synchronization. In the&nbsp;spirit of improving safety, this model will help you write more predictable code in Swift.”</div><div class=""><br class=""></div><div class="">Yet, data race can occur here:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; color: rgb(186, 45, 162); background-color: rgb(255, 255, 255);" class="">public<span style="" class=""> </span>class<span style="" class=""> MyClass {</span></div><div style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; <span style="color: #ba2da2" class="">private</span> <span style="color: #ba2da2" class="">var</span> _myArray: <span style="color: #703daa" class="">Array</span>&lt;<span style="color: #703daa" class="">Int</span>&gt; = []</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; <span style="color: #ba2da2" class="">private</span> <span style="color: #ba2da2" class="">var</span> _lock = <span style="color: #703daa" class="">NSLock</span>()</div><div style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; <span style="color: #ba2da2" class="">public</span> <span style="color: #ba2da2" class="">var</span> myArray: <span style="color: #703daa" class="">Array</span>&lt;<span style="color: #703daa" class="">Int</span>&gt; {</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: #4f8187" class="">lock</span>.<span style="color: #31595d" class="">lock</span>()</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ba2da2" class="">defer</span> {</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #4f8187" class="">lock</span>.<span style="color: #31595d" class="">unlock</span>()</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ba2da2" class="">let</span> copy = <span style="color: #4f8187" class="">_myArray</span></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ba2da2" class="">return</span> copy</div></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; }</div><div style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; <span style="color: #ba2da2" class="">public</span> <span style="color: #ba2da2" class="">func</span> doSomethingThatMutatesArray() {</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #4f8187" class="">_lock</span>.<span style="color: #3e1e81" class="">lock</span>()</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0); background-color: rgb(255, 255, 255);" class=""><span style="" class="">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #4f8187" class="">_myArray</span><span style="" class="">.</span><span style="color: #3e1e81" class="">append</span><span style="" class="">(</span><span style="color: #272ad8" class="">1</span><span style="" class="">) </span>// data race here: write of size 8 by thread 1</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #4f8187" class="">_lock</span>.<span style="color: #3e1e81" class="">unlock</span>()</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; }</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">}</div><div style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="color: #ba2da2" class="">let</span> myClass = <span style="color: #4f8187" class="">MyClass</span>()</div><div style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="color: #ba2da2" class="">func</span> mutateArray() {</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; color: rgb(49, 89, 93); background-color: rgb(255, 255, 255);" class=""><span style="" class="">&nbsp; &nbsp; </span><span style="color: #4f8187" class="">myClass</span><span style="" class="">.</span>doSomethingThatMutatesArray<span style="" class="">()</span></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; <span style="color: #ba2da2" class="">var</span> arrayCopy = <span style="color: #4f8187" class="">myClass</span>.<span style="color: #4f8187" class="">myArray</span></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0); background-color: rgb(255, 255, 255);" class=""><span style="" class="">&nbsp; &nbsp; arrayCopy.</span><span style="color: #3e1e81" class="">append</span><span style="" class="">(</span><span style="color: #272ad8" class="">2</span><span style="" class="">) </span>// data race here: read of size 8 by thread 10</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">}</div><div style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><span style="color: rgb(186, 45, 162);" class="">let</span>&nbsp;q1 =&nbsp;<span style="color: rgb(112, 61, 170);" class="">DispatchQueue</span>(label:&nbsp;<span style="color: rgb(209, 47, 27);" class="">"testQ1"</span>)</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><span style="color: rgb(186, 45, 162);" class="">let</span>&nbsp;q2 =&nbsp;<span style="color: rgb(112, 61, 170);" class="">DispatchQueue</span>(label:&nbsp;<span style="color: rgb(209, 47, 27);" class="">"testQ2"</span>)</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><span style="color: rgb(186, 45, 162);" class="">let</span>&nbsp;q3 =&nbsp;<span style="color: rgb(112, 61, 170);" class="">DispatchQueue</span>(label:&nbsp;<span style="color: rgb(209, 47, 27);" class="">"testQ3"</span>)</div><div style="font-family: Helvetica; margin: 0px; font-stretch: normal; line-height: normal; min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><span style="color: rgb(186, 45, 162);" class="">let</span>&nbsp;iterations =&nbsp;<span style="color: rgb(39, 42, 216);" class="">100_000</span></div><div style="font-family: Helvetica; margin: 0px; font-stretch: normal; line-height: normal; min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">q1.<span style="color: rgb(62, 30, 129);" class="">async</span>&nbsp;{</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp;&nbsp;<span style="color: rgb(186, 45, 162);" class="">for</span>&nbsp;<span style="color: rgb(186, 45, 162);" class="">_</span>&nbsp;<span style="color: rgb(186, 45, 162);" class="">in</span>&nbsp;<span style="color: rgb(39, 42, 216);" class="">0</span>..&lt;iterations {</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: rgb(49, 89, 93);" class="">mutateArray</span>()</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; }</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">}</div><div style="font-family: Helvetica; margin: 0px; font-stretch: normal; line-height: normal; min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">q2.<span style="color: rgb(62, 30, 129);" class="">async</span>&nbsp;{</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp;&nbsp;<span style="color: rgb(186, 45, 162);" class="">for</span>&nbsp;<span style="color: rgb(186, 45, 162);" class="">_</span>&nbsp;<span style="color: rgb(186, 45, 162);" class="">in</span>&nbsp;<span style="color: rgb(39, 42, 216);" class="">0</span>..&lt;iterations {</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: rgb(49, 89, 93);" class="">mutateArray</span>()</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; }</div></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">}</div><div style="font-family: Helvetica; margin: 0px; font-stretch: normal; line-height: normal; min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">q3.<span style="color: rgb(62, 30, 129);" class="">async</span>&nbsp;{</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp;&nbsp;<span style="color: rgb(186, 45, 162);" class="">for</span>&nbsp;<span style="color: rgb(186, 45, 162);" class="">_</span>&nbsp;<span style="color: rgb(186, 45, 162);" class="">in</span>&nbsp;<span style="color: rgb(39, 42, 216);" class="">0</span>..&lt;iterations {</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: rgb(49, 89, 93);" class="">mutateArray</span>()</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; }</div></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">}</div><div style="font-family: Helvetica; margin: 0px; font-stretch: normal; line-height: normal; min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><span style="color: rgb(186, 45, 162);" class="">for</span>&nbsp;<span style="color: rgb(186, 45, 162);" class="">_</span>&nbsp;<span style="color: rgb(186, 45, 162);" class="">in</span>&nbsp;<span style="color: rgb(39, 42, 216);" class="">0</span>..&lt;iterations {</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">&nbsp; &nbsp; &nbsp;<span style="color: rgb(49, 89, 93);" class="">mutateArray</span>()</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">}</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">q1.<span style="color: rgb(62, 30, 129);" class="">sync</span>&nbsp;{}</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">q2.<span style="color: rgb(62, 30, 129);" class="">sync</span>&nbsp;{}</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class="">q3.<span style="color: rgb(62, 30, 129);" class="">sync</span>&nbsp;{}</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><span style="color: rgb(62, 30, 129);" class="">NSLog</span>(<span style="color: rgb(209, 47, 27);" class="">"done"</span>)</div></div><div class=""><br class=""></div><div class="">It also can occur for instance if I replace the mutateArray() function with the following method:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="color: rgb(186, 45, 162);" class="">func</span>&nbsp;enumerateArray() {</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; color: rgb(49, 89, 93); background-color: rgb(255, 255, 255);" class=""><span style="" class="">&nbsp; &nbsp;&nbsp;</span><span style="color: rgb(79, 129, 135);" class="">myClass</span><span style="" class="">.</span>doSomethingThatMutatesArray<span style="" class="">()</span></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp;&nbsp;<span style="color: rgb(186, 45, 162);" class="">for</span>&nbsp;element&nbsp;<span style="color: rgb(186, 45, 162);" class="">in</span>&nbsp;<span style="color: rgb(79, 129, 135);" class="">myClass</span>.<span style="color: rgb(79, 129, 135);" class="">myArray</span>&nbsp;{ &nbsp;<span style="color: rgb(0, 132, 0);" class="">// data race here: read of size 8 by thread 5</span></div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<span style="color: rgb(186, 45, 162);" class="">let</span>&nbsp;<span style="color: rgb(186, 45, 162);" class="">_</span>&nbsp;= element</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">&nbsp; &nbsp;&nbsp;}</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class="">}</div><div style="margin: 0px; font-stretch: normal; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><br class=""></div><div style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);" class="">How can I return a “predictable” copy from the MyClass.myArray getter, so that I can later mutate the copy without synchronization like in the&nbsp;<span style="font-family: Menlo;" class="">mutateArray()</span>&nbsp;function?</div><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Dec 5, 2017, at 9:23 PM, Romain Jacquinot via swift-users &lt;<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>&gt; 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="">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&nbsp;var _myArray: Array&lt;Int&gt; = []</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>private&nbsp;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&lt;Int&gt; {</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&lt;T&gt; 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 =&nbsp;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 class=""><br class=""><blockquote type="cite" class=""><div class="">On Dec 5, 2017, at 8:22 PM, Jens Alfke &lt;<a href="mailto:jens@mooseyard.com" class="">jens@mooseyard.com</a>&gt; 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 &lt;<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>&gt; 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&nbsp;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></div>_______________________________________________<br class="">swift-users mailing list<br class=""><a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-users" class="">https://lists.swift.org/mailman/listinfo/swift-users</a><br class=""></div></blockquote></div><br class=""></div></div></div>_______________________________________________<br class="">swift-users mailing list<br class=""><a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-users" class="">https://lists.swift.org/mailman/listinfo/swift-users</a><br class=""></div></blockquote></div><br class=""></div></div></div></div></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></div></div></div></div></div></div></body></html>