<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><blockquote type="cite" class="">On Feb 22, 2017, at 1:41 PM, Charles Srstka via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class=""></blockquote><div><blockquote type="cite" class=""><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><div class="" applecontenteditable="true" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="">* Updating completedUnitCount atomically</div><div class=""><br class=""></div><div class="">The best practice here is to keep the progress object thread local. I think that updating one progress from multiple threads could be a code smell. Perhaps then you are doing several parts of the work and you should instead form a tree. This also leads in a direction where completed unit count is either 100% handed out to children or 100% controlled by your work-update-progress loop. Mixing the two leads to easy confusion about who is responsible for which portion. If you follow this rule, you never have to get the completed unit count, which means the race you describe does not exist.</div></div></div></div></blockquote><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"></div><div class="">NSProgress is designed to be thread-safe by protecting access to its properties with an NSLock, but it is not in fact thread-safe. It is making a promise to its users that it is not keeping. In addition, the lack of an atomic increment means that if you are getting data from an API that only reports deltas, you either have to get the old completedUnitCount, or keep track of the running total yourself. An atomic increment operation would not only improve thread safety, but it would improve the experience, since it would reduce the work the user needs to do, while remaining safe and performant.</div></div></div></blockquote></div><br class=""><div class="">One thing to add to this is that when dealing with async APIs that you don’t control, you don’t always know that things will be thread-local.</div><div class=""><br class=""></div><div class="">So if some library provides:</div><div class=""><br class=""></div><div class="">public func OpaqueAPI(input: SomeInput, dataHandler: (Data) -> ())</div><div class=""><br class=""></div><div class="">then in your client code:</div><div class=""><br class=""></div><div class="">let progress = Progress.discreteProgress(totalUnitCount: ...)</div><div class=""><br class=""></div><div class="">OpaqueAPI(input: blah) { data in</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>// Update my progress by data.count, but I don’t necessarily know what thread this will happen on, or that it will be the same one every time</div><div class="">}</div><div class=""><br class=""></div><div class="">So, now I have to protect either the progress or some running total var that I’m keeping with locks/mutexes/semaphores/sync queues/etc., adding a ton of boilerplate to the method.</div><div class=""><br class=""></div><div class="">Charles</div><div class=""><br class=""></div></body></html>