Understanding BlockedIndefinitelyOnMVar in Concurrent code
I asked this question on the ghc-users mailing list and got some helpful responses, but still don't understand what is happening in this code.
Essentially I am trying to understand how I can catch the exception BlockedIndefinitelyOnMVar to restore a lock that may have not been returned, and to understand this exception in general.
Here is some single-threaded code that does just that:
-- This raises the exception only once and the lock is successfully restored:
main1 = do
lock <- newMVar ()
lockPrint "good1" lock
takeMVar lock
putStrLn "main: took lock but didn't return it!"
-- exception is raised and lock is restored here:
lockPrint "good2" lock
--开发者_JS百科 no exception raised:
lockPrint "good3" lock
readMVar lock
putStrLn "great success"
lockPrint :: String -> MVar () -> IO ()
lockPrint name v = takePrint `finally` put
where put = putMVar v () >> putStrLn (name++": replaced lock")
takePrint = do
e <- try $ takeMVar v :: IO (Either BlockedIndefinitelyOnMVar ())
let printExc = putStrLn . ((name++": ")++) . show
printSuccess = const $ putStrLn (name++": success")
either printExc printSuccess e
And here is the version of main that exhibits the behavior I don't understand. In particular I'm not quite sure why the exception is being raised in main, although I see that the threads aren't really being scheduled as I imagine.
main0 = do
lock <- newMVar ()
forkIO $ lockPrint "good1" lock
threadDelay 100000
takeMVar lock
putStrLn "main: took lock but didn't return it!"
-- raises blocked indefinitely exception
forkIO $ lockPrint "good2" lock
-- this should raise no exception if we were successful above:
putStrLn "main: long pause..."
threadDelay 2000000
readMVar lock
putStrLn "great success"
I'm sorry I'm having trouble coming up with a simpler example. The above was compiled with: ghc --make -threaded -fforce-recomp experiments.hs
EDIT: Edward Z. Yang wrote a really lucid blog post on this today here. The upshot being that this exception can't really be relied on for doing anything fancy.
Trying to handle BlockedIndefinitelyOnMVar
doesn't sound like a good idea in the first place. It's easier to use withMVar
to ensure that the contents of the MVar
is always returned. With that, you shouldn't get this exception in the first place, unless you have a deadlock (which should be considered a bug and should be fixed in the code).
精彩评论