Peter,<br><br>Thanks for digging. In your results below, I see only three out of four threads killed even in the best case. Each time, there is no report of the 'sleep 2' thread being killed.<br><br>When I run your code on Linux (Ubuntu 8.10), everything looks great when run under ghci. If compiled, with and without -threaded and with and without +RTS -N2, I sometimes get four kill messages and sometimes fewer. In the latter case, I don't know if the other threads aren't getting killed or if they're killed but not reported.<br>
<br>For example (removing messages other than "Killed"):<br><br> conal@compy-doble:~/Haskell/Misc$ rm Threads.o ; ghc Threads.hs -threaded -o Threads && ./Threads +RTS -N2<br> Killed ThreadId 5<br>
Killed ThreadId 4<br><br> conal@compy-doble:~/Haskell/Misc$ ./Threads +RTS -N2<br> Killed ThreadId 5<br> Killed ThreadId 4<br> Killed ThreadId 7<br> Killed ThreadId 6<br><br> conal@compy-doble:~/Haskell/Misc$ ./Threads +RTS -N2<br>
Killed ThreadId 5<br> Killed ThreadId 7<br> Killed ThreadId 4<br> Killed ThreadId 6<br><br> conal@compy-doble:~/Haskell/Misc$ ./Threads +RTS -N2<br> Killed ThreadId 5<br> Killed ThreadId 4<br><br> conal@compy-doble:~/Haskell/Misc$ <br>
<br>Simon -- does this behavior look like a GHC bug to you?<br><br> - Conal<br><br><div class="gmail_quote">On Fri, Dec 19, 2008 at 9:45 AM, Peter Verswyvelen <span dir="ltr"><<a href="mailto:bugfact@gmail.com">bugfact@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div><div><div>I played a bit the the bracket function that timeout uses, but got strange results (both on Windows and OSX).</div>
<div><br></div><div>Ugly code fragment follows:</div><div><br></div><div>-%<-------------------------------------------------------------------------------------------------</div>
<div><br></div><div>import Prelude hiding (catch)</div><div><br></div><div>import Control.Concurrent</div><div>import Control.Concurrent.MVar</div><div>import Control.Exception</div><div>import System.IO</div><div>import Data.Char</div>
<div><br></div><div>withThread a b = bracket (forkIO a) kill (const b)</div><div> where</div><div> kill id = do</div><div> putStrLn ("Killing "++show id++"\n")</div><div> killThread id</div>
<div> putStrLn ("Killed "++show id++"\n")</div><div><br></div><div>race a b = do</div><div> v <- newEmptyMVar</div><div> let t x = x >>= putMVar v</div><div> withThread (t a) $ withThread (t b) $ takeMVar v</div>
<div class="Ih2E3d">
<div><br></div><div>forkPut :: IO a -> MVar a -> IO ThreadId</div><div>forkPut act v = forkIO ((act >>= putMVar v) `catch` uhandler `catch` bhandler)</div><div> where</div><div> uhandler (ErrorCall "Prelude.undefined") = return ()</div>
<div> uhandler err = throw err</div><div> bhandler BlockedOnDeadMVar = return ()</div><div><br></div></div><div>sleep n = do</div><div> tid <- myThreadId</div><div> putStrLn ("Sleeping "++show n++" sec on "++show tid++"\n")</div>
<div> threadDelay (n*1000000)</div><div> putStrLn ("Slept "++show n++" sec on "++show tid++"\n")</div><div><br></div><div>f = sleep 2 `race` sleep 3</div><div><br></div><div>g = f `race` sleep 1</div>
<div><br></div><div>main = do</div><div> hSetBuffering stdout LineBuffering</div><div> g</div><div> </div><div>-%<-------------------------------------------------------------------------------------------------</div>
<div><br></div><div>Here's the output when running with GHCI:</div><div> </div><div>C:\temp>runghc racetest</div><div>Sleeping 1 sec on ThreadId 26</div><div>Sleeping 2 sec on ThreadId 27</div><div>Sleeping 3 sec on ThreadId 28</div>
<div>Slept 1 sec on ThreadId 26</div><div>Killing ThreadId 26</div><div>Killed ThreadId 26</div><div>Killing ThreadId 25</div><div>Killed ThreadId 25</div><div>Killing ThreadId 28</div><div>Killed ThreadId 28</div><div><br>
</div><div>Fine, all threads got killed. </div><div><br></div><div>Here's the output from an EXE compiled with GHC -threaded, but run without +RTS -N2</div><div><br></div><div>C:\temp> racetest</div><div>Sleeping 1 sec on ThreadId 5</div>
<div>Sleeping 3 sec on ThreadId 7</div><div>Sleeping 2 sec on ThreadId 6</div><div>Slept 1 sec on ThreadId 5</div><div>Killing ThreadId 5</div><div>Killed ThreadId 5</div><div>Killing ThreadId 4</div><div>Killed ThreadId 4</div>
<div>Killing ThreadId 7</div><div><br></div><div>So "Killed ThreadId 7" is not printed here. What did I do wrong?</div><div><br></div><div>Here's the output from an EXE compiled with GHC -threaded, but run with +RTS -N2</div>
<div><br></div><div>C:\temp> racetest +RTS -N2</div><div>Sleeping 1 sec on ThreadId 5</div><div>Sleeping 3 sec on ThreadId 7</div><div>Sleeping 2 sec on ThreadId 6</div><div>Slept 1 sec on ThreadId 5</div><div><br></div>
<div>Killing ThreadId 5</div><div>Killed ThreadId 5</div><div>Killing ThreadId 4</div><div>Killed ThreadId 4</div><div>Killing ThreadId 7</div><div>Killed ThreadId 7</div><div><br></div><div>This works again. </div><div>
<br>
</div><div>Is this intended behavior?</div><div><br></div><div>Cheers,</div><div>Peter Verswyvelen</div><font color="#888888"><div>CTO - Anygma</div></font><div><div></div><div class="Wj3C7c"><div><br></div><div class="gmail_quote">
On Fri, Dec 19, 2008 at 10:48 AM, Simon Marlow <span dir="ltr"><<a href="mailto:marlowsd@gmail.com" target="_blank">marlowsd@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Sounds like you should use an exception handler so that when the parent dies it also kills its children. Be very careful with race conditions ;-)<br>
<br>
For a good example of how to do this sort of thing, see<br>
<br>
<a href="http://www.haskell.org/ghc/docs/latest/html/libraries/base/System-Timeout.html" target="_blank">http://www.haskell.org/ghc/docs/latest/html/libraries/base/System-Timeout.html</a><br>
<br>
the docs are sadly missing the source links at the moment, I'm not sure why, but you can find the source in<br>
<br>
<a href="http://darcs.haskell.org/packages/base/System/Timeout.hs" target="_blank">http://darcs.haskell.org/packages/base/System/Timeout.hs</a><br>
<br>
Cheers,<br>
Simon<br>
<br>
Conal Elliott wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div>
(I'm broadening the discussion to include haskell-cafe.)<br>
<br>
Andy -- What do you mean by "handling all thread forking locally"?<br>
<br>
- Conal<br>
<br></div><div><div></div><div>
On Thu, Dec 18, 2008 at 1:57 PM, Andy Gill <<a href="mailto:andygill@ku.edu" target="_blank">andygill@ku.edu</a> <mailto:<a href="mailto:andygill@ku.edu" target="_blank">andygill@ku.edu</a>>> wrote:<br>
<br>
Conal, et. al,<br>
<br>
I was looking for exactly this about 6~9 months ago. I got the<br>
suggestion to pose it as a challenge<br>
to the community by Duncan Coutts. What you need is thread groups,<br>
where for a ThreadId, you can send a signal<br>
to all its children, even missing generations if needed. <br>
I know of no way to fix this at the Haskell level without handling<br>
all thread forking locally. <br>
Perhaps a ICFP paper about the pending implementation :-) but I'm<br>
not sure about the research content here.<br>
<br>
Again, there is something deep about values with lifetimes. <br>
Andy Gill<br>
<br>
<br>
On Dec 18, 2008, at 3:43 PM, Conal Elliott wrote:<br>
<br>
</div></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div><div></div><div>
I realized in the shower this morning that there's a serious flaw<br>
in my unamb implementation as described in<br>
<a href="http://conal.net/blog/posts/functional-concurrency-with-unambiguous-choice" target="_blank">http://conal.net/blog/posts/functional-concurrency-with-unambiguous-choice</a>. I'm looking for ideas for fixing the flaw. Here's the code for<br>
racing computations:<br>
<br>
race :: IO a -> IO a -> IO a<br>
a `race` b = do v <- newEmptyMVar<br>
ta <- forkPut a v<br>
tb <- forkPut b v<br>
x <- takeMVar v<br>
killThread ta<br>
killThread tb<br>
return x<br>
<br>
forkPut :: IO a -> MVar a -> IO ThreadId<br>
forkPut act v = forkIO ((act >>= putMVar v) `catch` uhandler<br>
`catch` bhandler)<br>
where<br>
uhandler (ErrorCall "Prelude.undefined") = return ()<br>
uhandler err = throw err<br>
bhandler BlockedOnDeadMVar = return ()<br>
<br>
The problem is that each of the threads ta and tb may have spawned<br>
other threads, directly or indirectly. When I kill them, they<br>
don't get a chance to kill their sub-threads.<br>
<br>
Perhaps I want some form of garbage collection of threads, perhaps<br>
akin to Henry Baker's paper "The Incremental Garbage Collection of<br>
Processes". As with memory GC, dropping one consumer would<br>
sometimes result is cascading de-allocations. That cascade is<br>
missing from my implementation.<br>
<br>
Or maybe there's a simple and dependable manual solution,<br>
enhancing the method above.<br>
<br>
Any ideas?<br>
<br>
- Conal<br>
<br>
<br>
_______________________________________________<br>
Reactive mailing list<br></div></div>
<a href="mailto:Reactive@haskell.org" target="_blank">Reactive@haskell.org</a> <mailto:<a href="mailto:Reactive@haskell.org" target="_blank">Reactive@haskell.org</a>><div><br>
<a href="http://www.haskell.org/mailman/listinfo/reactive" target="_blank">http://www.haskell.org/mailman/listinfo/reactive</a><br>
</div></blockquote>
<br>
<br>
<br>
------------------------------------------------------------------------<br>
<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
</blockquote>
<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
</blockquote></div><br></div></div></div></div>
</blockquote></div><br>