<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=""><div><blockquote type="cite" class=""><div class="">On Dec 7, 2015, at 12:30 PM, Kevin Ballard via swift-corelibs-dev &lt;<a href="mailto:swift-corelibs-dev@swift.org" class="">swift-corelibs-dev@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; -webkit-line-break: after-white-space;" class="">


<title class=""></title>

<div class=""><div class="">On Mon, Dec 7, 2015, at 04:55 AM, Joakim Hassila via swift-corelibs-dev wrote:<br class=""></div>
<blockquote class=""><div class="">Secondly, we have extended the public libdispatch API internally with one<br class=""></div>
<div class="">more flavor of dispatching, let’s call it ‘dispatch_async_inline’ - the<br class=""></div>
<div class="">semantics being ‘perform the processing of the work synchronously if we<br class=""></div>
<div class="">wouldn’t block the calling thread, if we would block, instead perform the<br class=""></div>
<div class="">work as a normal dispatch_async’.<br class=""></div>
<div class="">&nbsp;</div>
<div class="">Would such a change be considered to be integrated, or should we keep our<br class=""></div>
<div class="">internal diffs indefinitely? Just to understand if it is worth the effort<br class=""></div>
<div class="">with a nicely packaged pull request or not...<br class=""></div>
<div class="">&nbsp;</div>
<div class="">The rationale for the API is that we are quite latency sensitive and want<br class=""></div>
<div class="">to use inline processing up until the point where we can’t keep up with<br class=""></div>
<div class="">the available work, at which point we would switch to asynchronous<br class=""></div>
<div class="">processing seamlessly (we have multiple producers). This means that the<br class=""></div>
<div class="">thread calling this API can be stolen for a significant amount of time<br class=""></div>
<div class="">(emptying the queue it was assigned to), but when the system is under<br class=""></div>
<div class="">‘light' load, we don’t need to incur the wakeup penalty for a completely<br class=""></div>
<div class="">asynchronous dispatch.<br class=""></div>
</blockquote><div class="">&nbsp;</div>
<div class="">I actually have an outstanding radar asking for this exact functionality. My proposal called it `dispatch_try_sync()`, which didn't actually call the dispatch_async() automatically but simply returned a boolean value telling you if it ran the code. My use-case here wasn't actually that I wanted to run the code async, but that I needed to do two operations on a realtime thread in any order, one of which needed to be on a queue, so I wanted to do something like<br class=""></div>
<div class="">&nbsp;</div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">BOOL done = dispatch_try_sync(queue, ^{ ... });</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">do_other_work();</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">if (!done) {</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">&nbsp;&nbsp;&nbsp; dispatch_sync(queue, ^{ ... });</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">}</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class="">&nbsp;</div>
<div class="">My radar is still open (<a href="rdar://problem/16436943" class="">rdar://problem/16436943</a>), but it got a response as follows:<br class=""></div>
<div class="">&nbsp;</div>
<blockquote class=""><div class="">I think the best way to "emulate" this is to use a DATA_OR source, and not semaphores or other things like that.<br class=""></div>
<div class="">&nbsp;</div>
<div class="">Most of the issues that I've seen with trylock() tends to be uses looking like this:<br class=""></div>
<div class="">&nbsp;</div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">again:</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">&nbsp; if (trylock()) {</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">&nbsp;&nbsp;&nbsp; do {</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clear_marker();</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do_job();</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">&nbsp;&nbsp;&nbsp;&nbsp; } while(has_marker());</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">&nbsp;&nbsp;&nbsp;&nbsp; unlock();</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">&nbsp; } else if (!has_marker()) {</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">&nbsp;&nbsp;&nbsp; set_marker();</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">&nbsp;&nbsp;&nbsp; goto again;</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class=""><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;">&nbsp; }</span><span class="font" style="font-family: menlo, consolas, &quot;courier new&quot;, monospace, sans-serif;"><br class=""></span></div>
<div class="">&nbsp;</div>
<div class="">and all unlockers check for the marker to do the said job before unlock basically.<br class=""></div>
<div class="">&nbsp;</div>
<div class="">The thing is, most of the people use that wrongly and don't loop properly making those coalescing checks racy, that's what dispatch DATA_OR sources are for.<br class=""></div>
<div class="">&nbsp;</div>
<div class="">Many other uses can also be replaced with a dispatch_async()<br class=""></div>
<div class="">&nbsp;</div>
<div class="">and it's very clear that the reporter can do exactly what he wants with a DATA_OR source. We should have a way to make sources acts as barriers (which I have a patch for) else we only provide half the required primitives.<br class=""></div>
<div class="">&nbsp;</div>
<div class="">I don't see a compelling use case that can't be solved elegantly with data sources today.<br class=""></div>
<div class="">&nbsp;</div>
<div class="">Using a DISPATCH_SOURCE_DATA_OR with a latch is a good alternative to what you are doing.<br class=""></div>
<div class="">&nbsp;</div>
<div class="">We are continuing to work on this issue, and will follow up with you again.</div></blockquote></div></div></div></blockquote><br class=""></div><div>Hi Joakim, Kevin,</div><div><br class=""></div><div>[ Full disclosure, I made that reply in&nbsp;<a href="rdar://problem/16436943" class="">rdar://problem/16436943</a>&nbsp;and your use case was slightly different IIRC but you’re right it’s a close enough problem&nbsp;]</div><div><br class=""></div><div><div class="">Dispatch internally has a notion of something that does almost that, called _dispatch_barrier_trysync_f[1]. However, it is used internally to serialize state changes on sources and queues such as setting the target queue or event handlers.</div><div class=""><br class=""></div><div class="">The problem is that this call bypasses the target queue hierarchy in its fastpath, which while it’s correct when changing the state of a given source or queue, is generally the wrong thing to do. Let’s consider this code assuming the dispatch_barrier_trysync()</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(193, 193, 193); background-color: rgb(0, 0, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #e4e4e4; background-color: #121212" class=""><br class=""></span></div><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(193, 193, 193); background-color: rgb(0, 0, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #e4e4e4; background-color: #121212" class="">&nbsp; &nbsp;&nbsp;</span><span style="font-variant-ligatures: no-common-ligatures; color: #2ee621" class="">dispatch_queue_t</span><span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9" class=""> outer = </span>dispatch_queue_create<span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: #fb3b1d" class="">"outer"</span><span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9" class="">, </span><span style="font-variant-ligatures: no-common-ligatures; color: #fb3b1d" class="">NULL</span><span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9" class="">);</span></div><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(193, 193, 193); background-color: rgb(0, 0, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #e4e4e4; background-color: #121212" class="">&nbsp; &nbsp; </span><span style="font-variant-ligatures: no-common-ligatures; color: #2ee621" class="">dispatch_queue_t</span><span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9" class=""> inner = </span>dispatch_queue_create<span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9" class="">(</span><span style="font-variant-ligatures: no-common-ligatures; color: #fb3b1d" class="">"inner"</span><span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9" class="">, </span><span style="font-variant-ligatures: no-common-ligatures; color: #fb3b1d" class="">NULL</span><span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9" class="">);</span></div><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(193, 193, 193); background-color: rgb(0, 0, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #e4e4e4; background-color: #121212" class="">&nbsp; &nbsp; </span>dispatch_set_target_queue<span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9" class="">(outer, inner);</span></div><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(245, 245, 245); background-color: rgb(0, 0, 0); min-height: 11px;" class=""><br class=""></div><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(193, 193, 193); background-color: rgb(0, 0, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #e4e4e4; background-color: #121212" class="">&nbsp; &nbsp; </span>dispatch_async<span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9" class="">(inner, ^{</span></div><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(215, 215, 255); background-color: rgb(18, 18, 18);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #e4e4e4" class="">&nbsp; &nbsp; &nbsp; &nbsp; </span>// write global state protected by inner</div><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(228, 228, 228); background-color: rgb(18, 18, 18);" class="">&nbsp; &nbsp; <span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9; background-color: #000000" class="">});</span></div><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(193, 193, 193); background-color: rgb(0, 0, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #e4e4e4; background-color: #121212" class="">&nbsp; &nbsp; </span>dispatch_barrier_trysync<span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9" class="">(outer, ^{</span></div><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(215, 215, 255); background-color: rgb(18, 18, 18);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #e4e4e4" class="">&nbsp; &nbsp; &nbsp; &nbsp; </span>// write global state protected by inner</div><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(228, 228, 228); background-color: rgb(18, 18, 18);" class="">&nbsp; &nbsp; <span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9; background-color: #000000" class="">});</span></div></div><div style="margin: 0px; font-size: 10px; line-height: normal; font-family: Menlo; color: rgb(228, 228, 228); background-color: rgb(18, 18, 18);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #e9e9e9; background-color: #000000" class=""><br class=""></span></div><div class=""><br class=""></div><div class="">Then if it works like the internal version we have today, the code above has a data race, which we’ll all agree is bad.</div><div class="">Or we do an API version that when the queue you do the trysync on is not targetted at a global root queue always go through async, and that is weird, because the performance characteristics would completely depend on the target queue hierarchy, which when layering and frameworks start to be at play, is a bad characteristic for a good API.</div><div class=""><br class=""></div><div class="">Or we don’t give up right away when the hierarchy is deep, but then that means that dispatch_trysync would need to be able to unwind all the locks it took, and then you have ordering issues because enqueuing that block that couldn’t run synchronously may end up being after another one and break the FIFO ordering of queues. Respecting this which is a desired property of our API and getting an efficient implementation are somehow at odds.</div><div class=""><div class=""><br class=""></div><div class="">The other argument against trysync that way, is that during testing trysync would almost always go through the non contended codepath, and lead developers to not realize that they should have taken copies of variables and the like (this is less of a problem on Darwin with obj-c and ARC), but trysync running on the same thread will hide that. except that once it starts being contended in production, it’ll bite you hard with memory corruption everywhere.</div><div class=""><br class=""></div></div><div class="">Technically what you’re after is that bringing up a new thread is very costly and that you’d rather use the one that’s asyncing the request because it will soon give up control. The wake up of a queue isn’t that expensive, in the sense that the overhead of dispatch_sync() in terms of memory barriers and locking is more or less comparable. What’s expensive is creating a thread to satisfy this enqueue.</div><div class=""><br class=""></div><div class="">In my opinion, to get the win you’re after, you’d rather want an async() version that if it wakes up the target queue hierarchy up to the root then you &nbsp;want to have more resistance in bringing up a new thread to satisfy that request. Fortunately, the overcommit property of queues could be used by a thread pool to decide to apply that resistance. There are various parts of the thread pool handling (especially without kernel work queues support) that could get some love to get these exact benefits without changing the API.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">[1] <a href="https://github.com/apple/swift-corelibs-libdispatch/blob/394d9a1c8be525cde8d9dd9fb8cef8308089b9c5/src/queue.c#L3089" class="">https://github.com/apple/swift-corelibs-libdispatch/blob/394d9a1c8be525cde8d9dd9fb8cef8308089b9c5/src/queue.c#L3089</a></div><div class=""><br class=""></div><div class=""><div class="">-Pierre</div></div></div><br class=""></body></html>