Fix risk of dead-lock in documentation of Control.Concurrent

Bas van Dijk v.dijk.bas at
Mon May 28 00:35:34 CEST 2012

The  current documentation of Control.Concurrent proposes a function
to wait for a child thread to complete:

   myForkIO :: IO () -> IO (MVar ())
   myForkIO io = do
     mvar <- newEmptyMVar
     forkIO (io `finally` putMVar mvar ())
     return mvar

This function has the risk of causing a dead-lock. If an asynchronous
exception if thrown before the putMVar exception handler is installed
the mvar will remain empty. This causes a dead-lock when the mvar is

The patch attached to the ticket [6126] fixes this problem by
correctly masking asynchronous exceptions before forking. Also,
instead of returning the mvar it returns a computation that waits for
the child thread to complete. This is safer than returning the mvar
itself since a user can't accidentally put the mvar (which will
dead-lock) or take the mvar (which when executed twice will

The attached patch additionally rewrites the function to wait for a
group of threads to complete. Instead of keeping a list of MVars, I
use a counter (stored in a TVar) that counts the number of running
threads. The counter is incremented when a thread if forked and
decremented when it completes. Waiting for the group of threads to
complete is accomplished by checking if the counter has reached 0 and
if not retry the transaction.




More information about the Libraries mailing list