Understanding behavior of BlockedIndefinitelyOnMVar exception

Brandon Simmons brandon.m.simmons at gmail.com
Mon Jul 25 00:56:12 CEST 2011

I'm trying to really understand how the BlockedIndefinitelyOnMVar
exception works in concurrent code as I would like to rely on it as a
useful runtime signal in a concurrency library I'm working on.

Here is some code illustrating a function restoring an abandoned lock
in a single-threaded program and works as I would expect:

-------- START CODE --------
module Main

import Control.Concurrent
import Control.Exception

-- This raises the exception only once and the lock is successfully restored:
main1 = do
    lock <- newMVar ()
    lockPrint "good1" lock
    badLockPrint "bad" lock
    -- exception is raised and lock is restored here:
    lockPrint "good2" lock
    -- no exception raised:
    lockPrint "good3" lock
    readMVar lock

lockPrint :: String -> MVar () -> IO ()
lockPrint name v =
    do e <- try $ takeMVar v :: IO (Either BlockedIndefinitelyOnMVar ())
       -- either print exception, or print name:
       either print (const $ putStrLn name) e
   `finally`  putMVar v ()

-- perhaps simulates an operation that died before it could return a lock:
badLockPrint :: String -> MVar () -> IO ()
badLockPrint s v = do
    takeMVar v
    putStrLn s
    -- Forgot to return the lock here!:
-------- END CODE --------

Now here is a variation of 'main' that forks the operations:

-------- START CODE --------
main0 = do
    lock <- newMVar ()
    forkIO $ lockPrint "good1" lock

    threadDelay 1000000
    forkIO $ badLockPrint "bad" lock

    -- these both raise blocked indefinitely exception
    threadDelay 1000000
    forkIO $ lockPrint "good2" lock
    threadDelay 1000000
    forkIO $ lockPrint "good3" lock

    threadDelay 1000000
-------- END CODE --------

What I think I've learned here is that the BlockedIndefinitelyOnMVar
exception is raised in all the blocked threads "at once" as it were.
That despite the fact that the handler code in 'lockPrint' restores
the lock for successive threads.

This would also seem to imply that putMVar's in an exception handler
don't stop the runtime from raising the BlockedIndefinitelyOnMVar. But
that doesn't really seem right.

Can anyone comment on the two conclusions above?

FWIW, this was an interesting related thread:

Brandon Simmons

More information about the Glasgow-haskell-users mailing list