concurrency

...now browsing by tag

 
 

Simple Futures in Haskell

Saturday, January 17th, 2009

One of those things I have to do fairly often in multithreaded programming is send off a whole bunch of threads to do their thing while I do something else on the main thread until they’re done. For example, imagine you’re downloading a bunch of images from the web, you don’t want to call httpGet one image right after another, because network resources are slow and processing them takes up almost no CPU time.  But on the other hand, forkIO doesn’t return anything, so a thread thunk will have to put its contents somewhere you can access them later.  Thus, my short, simple solution, far too small to bother putting up on Hackage:

module Control.Concurrent.Future where

import Control.Concurrent

future :: IO a -> IO (MVar a)
future thunk = do
    ref <- newEmptyMVar
    forkIO $ thunk >>= putMVar ref
    return ref

forceAll :: [MVar a] -> IO [a]
forceAll = mapM takeMVar

To use this, simply do a mapM (future thunk) parms, where thunk corresponds to (thunk :: IO a -> IO (MVar a)) and parms is the list of parameter sets (one item per thread), an [a].  This will spark off a whole bunch of threads that will do their thing while you continue along in the program.  Then when you need all the data, forceAll (also known as a “barrier” in multithreaded programming lingo) will take a list of asynchronous actions and force the program to wait for them all to complete.  If you need all the results immediately after you spark the threads, then the following simple line will do:

stuff' <- mapM future stuff >>= forceAll