<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Conal Elliott &#187; concurrency</title>
	<atom:link href="http://conal.net/blog/tag/concurrency/feed" rel="self" type="application/rss+xml" />
	<link>http://conal.net/blog</link>
	<description>Inspirations &#38; experiments, mainly about denotative/functional programming in Haskell</description>
	<lastBuildDate>Thu, 25 Jul 2019 18:15:11 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=4.1.17</generator>
	<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=conal&amp;popout=1&amp;url=http%3A%2F%2Fconal.net%2Fblog%2F&amp;language=en_US&amp;category=text&amp;title=Conal+Elliott&amp;description=Inspirations+%26amp%3B+experiments%2C+mainly+about+denotative%2Ffunctional+programming+in+Haskell&amp;tags=blog" type="text/html" />
	<item>
		<title>Smarter termination for thread racing</title>
		<link>http://conal.net/blog/posts/smarter-termination-for-thread-racing</link>
		<comments>http://conal.net/blog/posts/smarter-termination-for-thread-racing#comments</comments>
		<pubDate>Fri, 19 Dec 2008 08:11:23 +0000</pubDate>
		<dc:creator><![CDATA[Conal]]></dc:creator>
				<category><![CDATA[Functional programming]]></category>
		<category><![CDATA[concurrency]]></category>
		<category><![CDATA[unamb]]></category>

		<guid isPermaLink="false">http://conal.net/blog/?p=72</guid>
		<description><![CDATA[I realized in the shower this morning that there&#8217;s a serious flaw in my unamb implementation as described in Functional concurrency with unambiguous choice. Here&#8217;s the code for racing two computations: race :: IO a -&#62; IO a -&#62; IO a a `race` b = do v &#60;- newEmptyMVar ta &#60;- forkPut a v tb [&#8230;]]]></description>
				<content:encoded><![CDATA[<!-- 

Title: Smarter termination for thread racing

Tags: unamb, concurrency

URL: http://conal.net/blog/posts/smarter-termination-for-thread-racing/

-->

<!-- references -->

<!-- teaser -->

<p>I realized in the shower this morning that there&#8217;s a serious flaw in my unamb implementation as described in <em><a href="http://conal.net/blog/posts/functional-concurrency-with-unambiguous-choice/" title="blog post">Functional concurrency with unambiguous choice</a></em>.
Here&#8217;s the code for racing two computations:</p>

<pre><code>race :: IO a -&gt; IO a -&gt; IO a
a `race` b = do v  &lt;- newEmptyMVar
                ta &lt;- forkPut a v
                tb &lt;- forkPut b v
                x  &lt;- takeMVar  v
                killThread ta
                killThread tb
                return x

forkPut :: IO a -&gt; MVar a -&gt; IO ThreadId
forkPut act v = forkIO ((act &gt;&gt;= putMVar v) `catch` uhandler `catch` bhandler)
 where
   uhandler (ErrorCall "Prelude.undefined") = return ()
   uhandler err                             = throw err
   bhandler BlockedOnDeadMVar               = return ()
</code></pre>

<p>The problem is that each of the threads <code>ta</code> and <code>tb</code> may have spawned other threads, directly or indirectly.
When I kill them, they don&#8217;t get a chance to kill their sub-threads.
If the parent thread does get killed, it will most likely happen during the <code>takeMVar</code>.</p>

<p>My first thought was to use some form of garbage collection of threads, perhaps akin to Henry Baker&#8217;s paper <em><a href="ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-454.pdf" title="Paper by Henry Baker">The Incremental Garbage Collection of Processes</a></em>.
As with memory GC, dropping one consumer would sometimes result is cascading de-allocations.  That cascade is missing from my implementation above.</p>

<p>Or maybe there&#8217;s a simple and dependable manual solution, enhancing the method above.</p>

<p>I posted a note asking for ideas, and got the following suggestion from Peter Verswyvelen:</p>

<blockquote>
  <p>I thought that killing a thread was basically done by throwing a ThreadKilled exception using throwTo. Can&#8217;t these exception be caught?</p>
  
  <p>In C#/F# I usually use a similar technique: catch the exception that kills the thread, and perform cleanup.</p>
</blockquote>

<p>Playing with Peter&#8217;s suggestion works out very nicely, as described in this post.</p>

<!--
**Edits**:

* 2008-02-09: just fiddling around
-->

<!-- without a comment or something here, the last item above becomes a paragraph -->

<p><span id="more-72"></span></p>

<p>There is <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception.html#v:finally">a function</a> that takes a clean-up action to be executed even if the main computation is killed:</p>

<pre><code>finally :: IO a -&gt; IO b -&gt; IO a
</code></pre>

<p>Using this function, the <code>race</code> definition becomes a little shorter and more descriptive:</p>

<pre><code>a `race` b = do v  &lt;- newEmptyMVar
                ta &lt;- forkPut a v
                tb &lt;- forkPut b v
                takeMVar v `finally`
                  (killThread ta &gt;&gt; killThread tb)
</code></pre>

<p>This code is vulnerable to being killed after the first forkPut and before the second one, which would then leave the first thread running.
The following variation is a bit safer:</p>

<pre><code>a `race` b = do v  &lt;- newEmptyMVar
                ta &lt;- forkPut a v
                (do tb &lt;- forkPut b v
                    takeMVar v `finally` killThread tb)
                 `finally` killThread ta
</code></pre>

<p>Though I guess it&#8217;s still possible for the thread to get killed after the first fork and before the next statement begins.
Also, this code difficult to write and read.
The general pattern here is to fork a thread, do something else, and kill the thread.
Give that pattern a name:</p>

<pre><code>forking :: IO () -&gt; IO b -&gt; IO b
forking act k = do tid &lt;- forkIO act
                   k `finally` killThread tid
</code></pre>

<p>The post-fork action in both cases is to execute another action (<code>a</code> or <code>b</code>) and put the result into the mvar <code>v</code>.
Removing the <code>forkIO</code> from <code>forkPut</code>, leaves <code>putCatch</code>:</p>

<pre><code>putCatch :: IO a -&gt; MVar a -&gt; IO ()
putCatch act v = (act &gt;&gt;= putMVar v) `catch` uhandler `catch` bhandler
 where
   uhandler (ErrorCall "Prelude.undefined") = return ()
   uhandler err                             = throw err
   bhandler BlockedOnDeadMVar               = return ()
</code></pre>

<p>Combe <code>forking</code> and <code>putCatch</code> for convenience:</p>

<pre><code>forkingPut :: IO a -&gt; MVar a -&gt; IO b -&gt; IO b
forkingPut act v k = forking (putCatch act v) k
</code></pre>

<p>Or, in the style of <em><a href="http://conal.net/blog/posts/semantic-editor-combinators/" title="blog post">Semantic editor combinators</a></em>,</p>

<pre><code>forkingPut = (result.result) forking putCatch
</code></pre>

<p>Now the code is tidy and safe:</p>

<pre><code>a `race` b = do v &lt;- newEmptyMVar
                forkingPut a v $
                  forkingPut b v $
                    takeMVar v
</code></pre>

<p>Recall that there&#8217;s a very slim chance of the parent thread getting killed after spinning a child and before getting ready to kill the sub-thread (i.e., the <code>finally</code>).
If this case happens, we will not get an incorrect result.
Instead, an unnecessary thread will continue to run and write its result into an mvar that no one is reading.</p>
<p><a href="http://conal.net/blog/?flattrss_redirect&amp;id=72&amp;md5=bebe4781811e2accdd8ea0d2cbbcbb5f"><img src="http://conal.net/blog/wp-content/plugins/flattr/img/flattr-badge-white.png" srcset="http://conal.net/blog/wp-content/plugins/flattr/img/flattr-badge-white.png, http://conal.net/blog/wp-content/plugins/flattr/img/flattr-badge-white@2x.png 2xhttp://conal.net/blog/wp-content/plugins/flattr/img/flattr-badge-white.png, http://conal.net/blog/wp-content/plugins/flattr/img/flattr-badge-white@3x.png 3x" alt="Flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://conal.net/blog/posts/smarter-termination-for-thread-racing/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		<atom:link rel="payment" title="Flattr this!" href="https://flattr.com/submit/auto?user_id=conal&amp;popout=1&amp;url=http%3A%2F%2Fconal.net%2Fblog%2Fposts%2Fsmarter-termination-for-thread-racing&amp;language=en_GB&amp;category=text&amp;title=Smarter+termination+for+thread+racing&amp;description=I+realized+in+the+shower+this+morning+that+there%26%238217%3Bs+a+serious+flaw+in+my+unamb+implementation+as+described+in+Functional+concurrency+with+unambiguous+choice.+Here%26%238217%3Bs+the+code+for+racing+two...&amp;tags=concurrency%2Cunamb%2Cblog" type="text/html" />
	</item>
	</channel>
</rss>
