<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">Conal, et. al,<div><br></div><div>I was looking for exactly this about 6~9 months ago. I got the suggestion to pose it as a&nbsp;challenge</div><div>to the community by Duncan Coutts. What you need is thread groups, &nbsp;where for a ThreadId, you can send a signal</div><div>to all its children, even missing generations if needed.&nbsp;</div><div><br></div><div>I know of no way to fix this at the Haskell level without handling all&nbsp;thread forking locally.&nbsp;</div><div><br></div><div>Perhaps a ICFP paper about the pending implementation :-) but I'm not sure about the research content here.</div><div><br></div><div>Again, there is something deep about values with lifetimes.&nbsp;</div><div><br></div><div>Andy Gill</div><div><br></div><div><br><div><div><div>On Dec 18, 2008, at 3:43 PM, Conal Elliott wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite">I realized in the shower this morning that there's a serious flaw in my unamb implementation as described in <a href="http://conal.net/blog/posts/functional-concurrency-with-unambiguous-choice">http://conal.net/blog/posts/functional-concurrency-with-unambiguous-choice</a>.&nbsp; I'm looking for ideas for fixing the flaw.&nbsp; Here's the code for racing computations:<br> <br><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; race :: IO a -> IO a -> IO a</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; a `race` b = do v&nbsp; &lt;- newEmptyMVar</span><br style="font-family: courier new,monospace;"> <span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ta &lt;- forkPut a v</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tb &lt;- forkPut b v</span><br style="font-family: courier new,monospace;"> <span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x&nbsp; &lt;- takeMVar&nbsp; v</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; killThread ta</span><br style="font-family: courier new,monospace;"> <span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; killThread tb</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return x</span><br style="font-family: courier new,monospace;"> <br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; forkPut :: IO a -> MVar a -> IO ThreadId</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; forkPut act v = forkIO ((act >>= putMVar v) `catch` uhandler `catch` bhandler)</span><br style="font-family: courier new,monospace;"> <span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp;&nbsp; where</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uhandler (ErrorCall "Prelude.undefined") = return ()</span><br style="font-family: courier new,monospace;"> <span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uhandler err&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = throw err</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bhandler BlockedOnDeadMVar&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = return ()</span><br> <br>The problem is that each of the threads ta and tb may have spawned other threads, directly or indirectly.&nbsp; When I kill them, they don't get a chance to kill their sub-threads.<br><br>Perhaps I want some form of garbage collection of threads, perhaps akin to Henry Baker's paper "The Incremental Garbage Collection of Processes".&nbsp; As with memory GC, dropping one consumer would sometimes result is cascading de-allocations.&nbsp; That cascade is missing from my implementation.<br> <br>Or maybe there's a simple and dependable manual solution, enhancing the method above.<br><br>Any ideas?<br><br>&nbsp;&nbsp; - Conal<br><br><br> _______________________________________________<br>Reactive mailing list<br><a href="mailto:Reactive@haskell.org">Reactive@haskell.org</a><br><a href="http://www.haskell.org/mailman/listinfo/reactive">http://www.haskell.org/mailman/listinfo/reactive</a><br></blockquote></div><br></div></div></body></html>