
Hi!
On Wed, Nov 10, 2010 at 1:39 PM, Bas van Dijk
First of all, are you sure you're using a unique MVar for each thread? If not, there could be the danger of deadlock.
I am.
Finally the 'putMVar terminated ()' computation is performed.
Yes. But this should be done fast if MVar is empty, so putMVar does not block. And also MVar is filled, because takeMVar does not block at the end. So It is not that putMVar is interrupted (and thus no handler) but something after that.
Finally, your code has dangerous deadlock potential: Because you don't mask asynchronous exceptions before you fork it could be the case that an asynchronous exception is thrown to the thread before your exception handler is registered. This will cause the thread to abort without running your finalizer: 'putMVar terminated ()'. Your 'takeMVar terminated' will then deadlock because the terminated MVar will stay empty.
I know that (I read one post from you some time ago). It is in TODO commend before this code. I am waiting for GHC 7.0 for this because I do not like current block/unblock approach. Because blocked parts can still be interrupted, good example of that is takeMVar. The other is (almost?) any IO. So if code would be: block $ forkIO $ do putStrLn "Forked" (unblock doSomething) `finally` (putMVar terminated ()) There is a chance that putStrLn gets interrupted even with block. So for me it is better to have a big TODO warning before the code than to use block and believe that this is now fixed. And when I will add some code one year later I will have problems. Of course I could add a comment warning not to add any IO before finally. But I want to have a reason to switch to GHC 7.0. ;-) I am using such big hack for this: -- Big hack to prevent interruption: it simply retries interrupted computation uninterruptible :: IO a -> IO a uninterruptible a = block $ a `catch` (\(_ :: SomeException) -> uninterruptible a) So I can call "uninterruptible $ takeMVar terminated" and be really sure that I have waited for thread to terminate. Not that thread in its last breaths send me some exception which interrupted me waiting for it and thus not allowing it to terminate properly. Of course if you now that you do not want that your waiting is interrupted in any way. Maybe there could be an UserInterrupt exception to this uninterruptible way of handling exceptions. ;-)
I've made this same error and have seen others make it too. For this reason I created the threads[1] package to deal with it once and for all.
I know. I checked it. But was put off by mention of "unsafe".
Strange. It would help if you could show more of of your code.
I am attaching a sample program which shows this. I am using 6.12.3 on both Linux and Mac OS X. And I run this program with runhaskell Test.hs. Without "throwIO ThreadKilled" it outputs: Test.hs: MyTerminateException MVar was successfully taken With "throwIO ThreadKilled" is as expected, just: MVar was successfully taken So MVar is filled. What means that thread gets exception after that. But there is nothing after that. ;-) (At least nothing visible.) Mitar