【问题标题】:How to wait until forM_ finishes, when using TVar?使用 TVar 时如何等到 forM_ 完成?
【发布时间】:2017-04-28 00:14:58
【问题描述】:

我正在编写一个函数,其中我使用forM_ 处理一个列表,并将结果附加到一个TVar 列表中:

import Control.Concurrent.STM
import Control.Concurrent.STM.TVar
import Control.Concurrent (forkIO)
import Control.Monad (forM_)

insert :: a -> [a] -> [a]
insert = (:) -- stub

my_func_c :: (a -> a) -> [a] -> IO [a]
my_func_c my_function arr = do

    res_var <- atomically $ newTVar ([]::[a])

    forkIO $ forM_ arr $ \x -> atomically $ do
        let y = id $! my_function x
        modifyTVar res_var (insert y)

    atomically $ readTVar res_var

如果我用-threaded 编译它,结果总是空的。怎么可能等待线程完成?我不能使用MVarAsync。我必须使用TVar 或其他基于TVar 的数据结构来解决这个问题

【问题讨论】:

    标签: multithreading haskell concurrency stm tvar


    【解决方案1】:

    惯用的解决方案是使用TMVars:

    my_func_c :: (a -> a) -> [a] -> IO [a]
    my_func_c my_function arr = do
        res_var <- atomically $ newTVar []
        finished <- atomically $ newEmptyTMVar
    
        forkIO $ do
            forM_ arr $ \x -> atomically $ do
                let y = id $! my_function x
                modifyTVar res_var (insert y)
            atomically $ putTMVar finished ()
    
        atomically $ takeTMVar finished >> readTVar res_var
    

    但如果你真的只允许使用TVars,你可以用TVar Bool模拟TMVar ()

    my_func_c :: (a -> a) -> [a] -> IO [a]
    my_func_c my_function arr = do
        res_var <- atomically $ newTVar []
        finished <- atomically $ newTVar False
    
        forkIO $ do
            forM_ arr $ \x -> atomically $ do
                let y = id $! my_function x
                modifyTVar res_var (insert y)
            atomically $ writeTVar finished True
    
        atomically $ waitTVar finished >> readTVar res_var
    
    waitTVar :: TVar Bool -> STM ()
    waitTVar tv = do
        finished <- readTVar tv
        unless finished retry
    

    在底层,TMVar a is just a TVar (Maybe a) (so TMVar () ~ TVar (Maybe ()) ~ TVar Bool) 和 takeTMVar doing a readTVar and a retry,因此上述两种解决方案在操作上完全等效。

    【讨论】:

    • 为什么每个 forM_ 函数调用都不需要writeTVar finished True?为什么在forM_之外?
    • 重点是你writeTVar finished True / putTMVar finished 当你完全完成时,即在计算出所有结果之后。请注意,如果在 forM_ 内部,所有元素都在单独的线程中处理(我假设您会在实际应用中这样做),这也可以工作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 2019-05-11
    • 2016-06-17
    • 2012-05-18
    • 2013-01-28
    • 2021-12-24
    • 1970-01-01
    相关资源
    最近更新 更多