0

我目前正在运行未知数量的工作人员,产生未知数量的结果,如果新结果比以前的结果更好,这些结果将被放入 MVar 并打印。这发生在printMaxResult下面显示的函数中。

main = do
    startTime <- getCurrentTime

    -- Read problem
    numbers <-  parseList
    target <-  parseTargetNumber
    -- Create mvar to communicate
    mvar <- newEmptyMVar

    -- Start solving the actual problem
    -- The solve methods will write their results
    -- into the given mvar
    forkIO $ SimpleAdd.solve (Problem target numbers) mvar
    forkIO $ IncrementDecrement.solve (Problem target numbers) mvar incOps decOps

    -- Read the first result and use it to go into the "main loop"
    expr <- takeMVar mvar
    debugPrintExpr expr startTime

    printMaxResult mvar expr startTime

    return ()

-- Extracts a new result from the given mvar and compares
-- it with the previous result. If the new result has a
-- better score it remembers it and prints it.
printMaxResult :: MVar Expr -> Expr ->  UTCTime -> IO ()
printMaxResult mvar expr startTime = do
    newExpr <- takeMVar mvar
    if score newExpr > score expr
        then do
            debugPrintExpr newExpr startTime
            printMaxResult mvar newExpr startTime
        else
            printMaxResult mvar expr startTime

问题是,一旦所有线程完成,程序就会崩溃,但出现以下异常:main: thread blocked indefinitely in an MVar operation. 当然,这条消息是正确的:MVar 不可能随时接收到一些新的输入。

但是我该如何优雅地处理这种情况呢?我可以处理该异常并执行“exit(0)”之类的操作。我试图了解异常处理在 Haskell 中是如何工作的,但我无法真正理解它。

4

2 回答 2

1

这正是pipes-concurrency旨在解决的问题:它允许您编写避免死锁的并发代码。

就像你提到的那样,写这样的东西似乎是不可能的,因为没有办法静态地知道MVar将来可能不会使用。解决此问题的方法pipes-concurrency是使用代码检测并发通道,该代码检测通道的输入端或输出端何时被垃圾收集。这允许它通知通道的另一端退出并避免触发死锁。

我建议您阅读pipes-concurrency教程,该教程非常详细。关于终止的第三部分与您刚刚描述的问题特别相关,它解释了如何pipes-concurrency在所有上游编写器完成后终止侦听器。

pipes-concurrency教程假定您对pipes库有基本的了解,因此如果您是新手,pipes那么您可能还想阅读官方pipes教程

于 2013-11-08T18:06:38.203 回答
1

穷人的协议是让你MVar携带两种消息:一种是新候选人的通知(可能会或可能不会比你迄今为止看到的最好的),另一种是通知之一您的线程已完成产生候选人。因此,您的两个求解线程可能如下所示:

solve mvar = do
    -- do some complicated work and report some candidates
    replicateM_ 3000 $ putMVar mvar (Just 42)
    -- when you're done, say so
    putMVar mvar Nothing

您的调试线程如下所示:

printMaxResult mvar expr 0 startTime = return ()
printMaxResult mvar expr numRunning startTime = do
    v <- mvar
    case v of
        Nothing -> printMaxResult mvar expr (numRunning-1) startTime
        Just newExpr | score newExpr > score expr -> ...
                     | otherwise                  -> ...
于 2013-11-08T18:56:36.353 回答