如何强制主线程等待其所有子线程在Haskell中完成

Amm*_*osh 8 multithreading haskell

在下面的Haskell代码中,如何强制主线程等待所有子线程完成.

我无法使用此链接中的"终止程序"部分中给出的forkFinally:(http://hackage.haskell.org/package/base-4.7.0.2/docs/Control-Concurrent.html).

使用TMVar时,我得到了理想的结果.但是我想和TVar一起做这件事.请帮忙.

module Main
where
import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM

type TInt = TVar Int

transTest :: TInt -> Int -> IO ()
transTest n t = do 
    atomically $ do 
        t1 <- readTVar n                    
        doSomeJob t
        t2 <- readTVar n
        writeTVar n t

doSomeJob :: Int -> STM ()
doSomeJob t = do
    x <- newTVar 0
    let l = 10^6*t
    forM_ [1..l] (\i -> do 
        writeTVar x i )            

main :: IO ()
main = do
    n <- newTVarIO 0

    let v = 5
    forkIO (transTest n v)

    let v = 3
    forkIO (transTest n v)

    let v = 7
    forkIO (transTest n v)

    let v = 1
    forkIO (transTest n v)  


    r <- atomically $ readTVar n
    putStrLn("Last updated value = " ++ (show r))
Run Code Online (Sandbox Code Playgroud)

Fre*_*abe 17

我过去做的是为每个分叉线程创建一个小的MVar然后forkFinally用来分叉线程,这样在最后,每个线程都会将一个虚拟值放入MVar(即我使用MVar作为同步原语) ).然后我可以打电话takeMVar给那些MV等待.

我把它包装成一个小帮手函数:

forkThread :: IO () -> IO (MVar ())
forkThread proc = do
    handle <- newEmptyMVar
    _ <- forkFinally proc (\_ -> putMVar handle ())
    return handle
Run Code Online (Sandbox Code Playgroud)

使用它,您的代码可以更改为类似的

-- Fork four threads
threads <- forM [5, 3, 7, 1] (\v -> forkThread (transTest n v))

-- Wait for all of them
mapM_ takeMVar threads
Run Code Online (Sandbox Code Playgroud)

然而,那是在我阅读Simon Marlow撰写的(最优秀的)"Haskell中的并行和并发编程"一书之前,这本书让我了解了异步包.该软件包提供了一个抽象,它不仅可以处理所有这些事情,因此您可以只编写

-- Runs 'transTest n {5,3,7,1}' in parallel and waits for all threads
_ <- mapConcurrently (transTest n) [5, 3, 7, 1]
Run Code Online (Sandbox Code Playgroud)

...它还处理诸如(异步)异常之类的事情.