了解并发代码中的BlockedIndefinitelyOnMVar

时间:2011-07-27 15:47:37

标签: haskell concurrency ghc

我在ghc-users邮件列表上的asked this question并获得了一些有用的回复,但仍然不明白此代码中发生了什么。

基本上我试图理解如何捕获异常BlockedIndefinitelyOnMVar以恢复可能尚未返回的锁定,以及一般地理解此异常。

以下是一些单线程代码:

-- 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
    -- 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

以下是展示我不理解的行为的主要版本。特别是我不太确定为什么在main中引发异常,尽管我发现线程并没有像我想象的那样被安排。

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"

对不起,我很难想出一个更简单的例子。以上内容编译为:ghc --make -threaded -fforce-recomp experiments.hs


编辑:Edward Z. Yang今天在这里写了一篇非常清晰的博客post。结果是,这个例外无法真正依赖于做任何奇特的事情。

1 个答案:

答案 0 :(得分:3)

首先尝试处理BlockedIndefinitelyOnMVar听起来不是一个好主意。使用withMVar更容易确保始终返回MVar的内容。有了这个,你不应该首先得到这个异常,除非你有一个死锁(应该被认为是一个错误,应该在代码中修复)。