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.
Frerich raabe
source share