Weird behavior of the NonTermination exception

Simon Marlow marlowsd at gmail.com
Fri May 4 14:12:15 CEST 2012


On 03/05/2012 17:14, Bas van Dijk wrote:
> On 3 May 2012 17:31, Edward Z. Yang<ezyang at mit.edu>  wrote:
>> Excerpts from Bas van Dijk's message of Thu May 03 11:10:38 -0400 2012:
>>> As can be seen, the putMVar is executed successfully. So why do I get
>>> the message: "thread blocked indefinitely in an MVar operation"?
>>
>> GHC will send BlockedIndefinitelyOnMVar to all threads involved
>> in the deadlock, so it's not unusual that this can interact with
>> error handlers to cause the system to become undeadlocked.
>
> But why is the BlockedIndefinitelyOnMVar thrown in the first place?
> According to the its documentation and your very enlightening article
> it is thrown when:
>
> "The thread is blocked on an MVar, but there are no other references
> to the MVar so it can't ever continue."
>
> The first condition holds for the main thread since it's executing
> takeMVar. But the second condition doesn't hold since the forked
> thread still has a reference to the MVar.

The forked thread is deadlocked, so the MVar is considered unreachable 
and the main thread is also unreachable.  Hence both threads get sent 
the exception.

The RTS does this analysis using the GC, tracing the reachable objects 
starting from the roots.  It then send an exception to any threads which 
were not reachable, which in this case is both the main thread and the 
child, since neither is reachable.

We (the user) knows that waking up the child thread will unblock the 
main thread, but the RTS doesn't know this, and it's not clear how it 
could find out easily (i.e. without multiple scans of the heap).

Cheers,
	Simon




> I just tried delaying the thread before the putMVar:
>
> -------------------------------------------------
> main :: IO ()
> main = do
>    mv<- newEmptyMVar
>    _<- forkIO $ do
>           catch action
>                 (\e ->  putStrLn $ "I solved the Halting Problem: " ++
>                                   show (e :: SomeException))
>           putStrLn "Delaying for 2 seconds..."
>           threadDelay 2000000
>           putStrLn "putting MVar..."
>           putMVar mv ()
>           putStrLn "putted MVar"
>    takeMVar mv
> -------------------------------------------------
>
> Now I get the following output:
>
> loop: thread blocked indefinitely in an MVar operation
> I solved the Halting Problem:<<loop>>
> Delaying for 2 seconds...
>
> Now it seems the thread is killed while delaying. But why is it
> killed? It could be a BlockedIndefinitelyOnMVar that is thrown.
> However I get the same output when I catch and print all exceptions in
> the forked thread:
>
> main :: IO ()
> main = do
>    mv<- newEmptyMVar
>    _<- forkIO $
>           handle (\e ->  putStrLn $ "Oh nooo:" ++
>                                    show (e :: SomeException)) $ do
>             catch action
>                   (\e ->  putStrLn $ "I solved the Halting Problem: " ++
>                                     show (e :: SomeException))
>             putStrLn "Delaying for 2 seconds..."
>             threadDelay 2000000
>             putStrLn "putting MVar..."
>             putMVar mv ()
>             putStrLn "putted MVar"
>    takeMVar mv
>
> Bas
>
> _______________________________________________
> Glasgow-haskell-users mailing list
> Glasgow-haskell-users at haskell.org
> http://www.haskell.org/mailman/listinfo/glasgow-haskell-users




More information about the Glasgow-haskell-users mailing list