Small typo in the second sample code. Should read: return try closure(&_elements)
> Begin forwarded message: > > From: Romain Jacquinot via swift-users <swift-users@swift.org> > Subject: [swift-users] Data races with copy-on-write > Date: December 5, 2017 at 11:20:46 AM GMT+1 > To: swift-users@swift.org > Reply-To: Romain Jacquinot <rjacqui...@me.com> > > Hi, > > I'm trying to better understand how copy-on-write works, especially in a > multithreaded environment, but there are a few things that confuse me. > > From the documentation, it is said that: > "If the instance passed as object is being accessed by multiple threads > simultaneously, isKnownUniquelyReferenced(_:) may still return true. > Therefore, you must only call this function from mutating methods with > appropriate thread synchronization. That will ensure that > isKnownUniquelyReferenced(_:) only returns true when there is really one > accessor, or when there is a race condition, which is already undefined > behavior." > > Let's consider this sample code: > > func mutateArray(_ array: [Int]) { > var elements = array > elements.append(1) > } > > let q1 = DispatchQueue(label: "testQ1") > let q2 = DispatchQueue(label: "testQ2") > let q3 = DispatchQueue(label: "testQ3") > > let iterations = 1000 > > var array: [Int] = [1, 2, 3] > > q1.async { > for _ in 0..<iterations { > mutateArray(array) > } > } > > q2.async { > for _ in 0..<iterations { > mutateArray(array) > } > } > > q3.async { > for _ in 0..<iterations { > mutateArray(array) > } > } > > // ... > > From what I understand, since Array<T> implements copy-on-write, the array > should be copied only when the mutating append(_:) method is called in > mutateArray(_:). Therefore, isKnownUniquelyReferenced(_:) should be called to > determine whether a copy is required or not. > > However, it is being accessed by multiple threads simultaneously, which may > cause a race condition, right? So why does the thread sanitizer never detect > a race condition here? Is there some compiler optimization going on here? > > On the other hand, the thread sanitizer always detects a race condition, for > instance, if I add the following code to mutate directly the array: > > for _ in 0..<iterations { > array.append(1) > } > > In this case, is it because I mutate the array buffer that is being copied > from other threads? > > > Even strangier, let's consider the following sample code: > > class SynchronizedArray<Element> { > > // [...] > > private var lock = NSLock() > private var _elements: Array<Element> > > var elements: Array<Element> { > lock.lock() > defer { lock.unlock() } > return _elements > } > > @discardableResult > public final func access<R>(_ closure: (inout T) throws -> R) rethrows > -> R { > lock.lock() > defer { lock.unlock() } > return try closure(&_value) > } > } > > let syncArray = SynchronizedArray<Int>() > > func mutateArray() { > syncArray.access { array in > array.append(1) > } > > var elements = syncArray.elements > var copy = elements // [X] no race condition detected by TSan when I > add this line > elements.append(1) // race condition detected by TSan (if previous line > is missing) > } > > // Call mutateArray() from multiple threads like in the first sample code. > > The line marked with [X] does nothing useful, yet adding this line prevents > the race condition at the next line to be detected by the thread sanitizer. > Is this again because of some compiler optimization? > > However, when the array buffer is being copied, we can mutate the same buffer > with the append(_:) method, right? So, shouldn't the thread sanitizer detect > a race condition here? > > Please let me know if I ever misunderstood how copy-on-write works in Swift. > > Also, I'd like to know: > - besides capture lists, what are the correct ways to pass a copy-on-write > value between threads? > - for thread-safe classes that expose an array as a property, should I always > copy the private array variable before returning it from the public getter? > If so, is there any recommended way to force-copy a value type in Swift ? > > Any help would be greatly appreciated. > Thanks. > > Note: I'm using Swift 4 with the latest Xcode version (9.2 (9C40b)) and the > thread sanitizer enabled. > > _______________________________________________ > swift-users mailing list > swift-users@swift.org > https://lists.swift.org/mailman/listinfo/swift-users
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users