如何强制主线程等待其所有子线程在 Haskell 内完成
How to force main thread to wait for all its child threads finish in Haskell
在下面的Haskell代码中,如何强制主线程等待它的所有子线程完成。
我无法使用 "Terminating the Program" 部分给出的 forkFinally link: (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))
我过去所做的是为每个分叉的线程创建一个小的 MVar,然后使用 forkFinally
分叉线程,这样在最后,每个线程都会将一个虚拟值放入 MVar (即我使用 MVar 作为同步原语)。然后我可以在这些 MVar 上调用 takeMVar
等待。
我把它包装成一个小辅助函数:
forkThread :: IO () -> IO (MVar ())
forkThread proc = do
handle <- newEmptyMVar
_ <- forkFinally proc (\_ -> putMVar handle ())
return handle
使用它,您的代码可以更改为类似
-- Fork four threads
threads <- forM [5, 3, 7, 1] (\v -> forkThread (transTest n v))
-- Wait for all of them
mapM_ takeMVar threads
但是,那是在我阅读 Simon Marlow 的(最优秀的)书 "Parallel and Concurrent Programming in Haskell" 之前,这本书让我意识到 async 包。该包提供了一个抽象,它不仅处理所有这些事情,所以你可以只写
-- Runs 'transTest n {5,3,7,1}' in parallel and waits for all threads
_ <- mapConcurrently (transTest n) [5, 3, 7, 1]
...它还处理诸如(异步)异常之类的事情。
在下面的Haskell代码中,如何强制主线程等待它的所有子线程完成。
我无法使用 "Terminating the Program" 部分给出的 forkFinally link: (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))
我过去所做的是为每个分叉的线程创建一个小的 MVar,然后使用 forkFinally
分叉线程,这样在最后,每个线程都会将一个虚拟值放入 MVar (即我使用 MVar 作为同步原语)。然后我可以在这些 MVar 上调用 takeMVar
等待。
我把它包装成一个小辅助函数:
forkThread :: IO () -> IO (MVar ())
forkThread proc = do
handle <- newEmptyMVar
_ <- forkFinally proc (\_ -> putMVar handle ())
return handle
使用它,您的代码可以更改为类似
-- Fork four threads
threads <- forM [5, 3, 7, 1] (\v -> forkThread (transTest n v))
-- Wait for all of them
mapM_ takeMVar threads
但是,那是在我阅读 Simon Marlow 的(最优秀的)书 "Parallel and Concurrent Programming in Haskell" 之前,这本书让我意识到 async 包。该包提供了一个抽象,它不仅处理所有这些事情,所以你可以只写
-- Runs 'transTest n {5,3,7,1}' in parallel and waits for all threads
_ <- mapConcurrently (transTest n) [5, 3, 7, 1]
...它还处理诸如(异步)异常之类的事情。