1

我正在编写一个函数,在其中使用 处理列表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

4

1 回答 1

3

惯用的解决方案是使用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

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

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只是 aTVar (Maybe a)(所以TMVar ()~~ )做 a和 a,所以上述两种解决方案在操作上是完全等价的TVar (Maybe ())TVar BooltakeTMVarreadTVarretry

于 2017-04-28T02:13:42.183 回答