
Don't forget to block asynchronous exception _before_ you fork in:
tid <- forkIO (someWorkToDo `finally` putMVar mv ())
Otherwise an asynchronous exception might be thrown to the thread
_before_ the 'putMVar mv ()' exception handler is installed leaving
your main thread in a dead-lock!
You can use the threads library which correctly abstracts over this pattern:
http://hackage.haskell.org/package/threads
Regards,
Bas
On Wed, Sep 15, 2010 at 2:23 AM, Gregory Collins
Mitar
writes: Hi!
On Tue, Sep 14, 2010 at 11:46 PM, Bas van Dijk
wrote: Note that killing the main thread will also kill all other threads. See:
Yes. But how does those other threads have time to cleanup is my question.
What we do in Snap is this: the master thread has a catch handler which catches the AsyncException generated by the call to killThread. When we get this, we instruct any service loop threads to exit, and they all wait for service threads to terminate (currently by sleep-polling a connections table, which I should probably fix...). Then the master thread exits by just returning.
Note that I think the "main thread being killed kills all threads" issue can be circumvented by using a little gadget like this:
------------------------------------------------------------------------ someWorkToDo :: IO () someWorkToDo = someStuff `catch` cleanupHandler
main :: IO () main = do mv <- newEmptyMVar tid <- forkIO (someWorkToDo `finally` putMVar mv ())
-- wait on thread to finish; any exception here is probably an -- AsyncException, so kill the someWorkToDo master thread -- yourself and wait on the mvar again
takeMVar mv `catch` \(e::SomeException) -> do killThread tid takeMVar mv ------------------------------------------------------------------------
At least, this is what we do in our webserver, and it seems to work fine -- users complain about the delay involved in our slow cleanup handler when they ctrl-c the server. :)
G -- Gregory Collins