了解并发代码中的BlockedIndefinitelyOnMVar [英] Understanding BlockedIndefinitelyOnMVar in Concurrent code

查看:154
本文介绍了了解并发代码中的BlockedIndefinitelyOnMVar的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问这个问题 ghc用户邮件列表,并得到了一些有用的回应,但仍不明白在这段代码中发生了什么。



基本上,我想了解如何捕捉例外BlockedIndefinitelyOnMVar来恢复一个可能还没有被返回的锁,并且通常理解这个异常。



下面是一些单线程代码: p>

   - 这只会引发一次异常并且成功恢复锁定:
main1 = do
lock< ; - newMVar()
lockPrintgood1锁定
takeMVar锁定
putStrLnmain:锁定但未返回!
- 引发异常并在此恢复锁定:
lockPrintgood2锁定
- 未引发异常:
lockPrintgood3锁定
readMVar锁定
putStrLn巨大成功

lockPrint :: String - > MVar() - > IO()
lockPrint name v = takePrint`finally`把
放在put = putMVar v()>> putStrLn(name ++:locked lock)
takePrint = do
e < - try $ takeMVar v :: IO(BlockedIndefinitelyOnMVar())
let printExc = putStrLn。 ((名称++:)++)。 show
printSuccess = const $ putStrLn(name ++:success)
printExc printSuccess e

以下是展示我不明白的行为的主版本。特别是我不太清楚为什么这个异常会在main中被提出,尽管我发现这些线程并没有像我想象的那样真正被安排好。

  main0 = do 
lock< - newMVar()
forkIO $ lockPrintgood1锁定

threadDelay 100000
takeMVar锁定
putStrLnmain:锁定但未返回!

- 无限期地引发无限例外
forkIO $ lockPrintgood2锁定

- 如果我们成功的话,这应该不会引发异常:
putStrLnmain:long pause ...
threadDelay 2000000
readMVar lock
putStrLn巨大成功

很抱歉,我无法提供一个更简单的例子。上面的代码是用下面的代码编译的: ghc --make -threaded -fforce-recomp experiments.hs




编辑:Edward Z. Yang写了一篇非常清晰的博客博文今天在这里。结果是,这个异常不能真正依赖于做任何事情。

解决方案

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


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

这篇关于了解并发代码中的BlockedIndefinitelyOnMVar的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆