How to force main thread to wait for all its child threads finish in Haskell

白昼怎懂夜的黑 提交于 2020-01-22 11:59:46

问题


In the following Haskell code, how to force main thread to wait till all its child threads finish.

I could not able to use forkFinally as given in the section "Terminating the Program" here in this link: (http://hackage.haskell.org/package/base-4.7.0.2/docs/Control-Concurrent.html).

I get desired result when using TMVar. But I want to do this with TVar. Please help.

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))

回答1:


What I did in the past was to create a little MVar for each forked thread and then use forkFinally to fork the threads such that at the very end, each thread would put a dummy value into the MVar (i.e. I used the MVar as a synchronisation primitive). I could then call takeMVar on those MVars to wait.

I wrapped it into a little helper function:

forkThread :: IO () -> IO (MVar ())
forkThread proc = do
    handle <- newEmptyMVar
    _ <- forkFinally proc (\_ -> putMVar handle ())
    return handle

Using this, your code could be changed to something like

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

-- Wait for all of them
mapM_ takeMVar threads

However, that was before I read the (most excellent) book "Parallel and Concurrent Programming in Haskell" by Simon Marlow, which made me aware of the async package. The package provides an abstraction which not only takes care of all these things, so you can write just

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

...it also takes care of things such as (asynchronous) exceptions.



来源:https://stackoverflow.com/questions/28169297/how-to-force-main-thread-to-wait-for-all-its-child-threads-finish-in-haskell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!