How to make the main thread wait for all child threads to complete in Haskell

In the following Haskell code, how to make the main thread wait for all its child threads to complete.

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

I get the desired result when using TMVar. But I want to do it 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 nt = do atomically $ do t1 <- readTVar n doSomeJob t t2 <- readTVar n writeTVar nt doSomeJob :: Int -> STM () doSomeJob t = do x <- newTVar 0 let l = 10^6*t forM_ [1..l] (\i -> do writeTVar xi ) main :: IO () main = do n <- newTVarIO 0 let v = 5 forkIO (transTest nv) let v = 3 forkIO (transTest nv) let v = 7 forkIO (transTest nv) let v = 1 forkIO (transTest nv) r <- atomically $ readTVar n putStrLn("Last updated value = " ++ (show r)) 
+7
multithreading haskell
source share
1 answer

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

I wrapped it in a small helper function:

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

Using this, your code can be changed to something like

 -- Fork four threads threads <- forM [5, 3, 7, 1] (\v -> forkThread (transTest nv)) -- Wait for all of them mapM_ takeMVar threads 

However, this was before I read the (most excellent) book, Parallel and Parallel Programming at Haskell, by Simon Marlowe, in which I learned about async . The package provides an abstraction that not only takes care of all these things, so you can write simply

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

... he also takes care of things like (asynchronous) exceptions.

+16
source share

All Articles