Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe parallel use of MVector/IOVector from Haskell vector package

Tags:

haskell

Can I safely assign to non-overlapping indices of an IOVector (from the Haskell vector package) from multiple parallel threads, or do I need an additional mutex?

Background: I want to run a collection of IO computations in parallel and then record all the results. I started by returning the results in a list, but this seems like the wrong data structure. So I am looking to use an IOVector from the vector package to store the results.

My question is, can I write something like:

runPar :: [IO a] -> IO (IOVector a)
runPar tasks = do
  v <- new (length tasks)
  mapM forkIO [task >>= write v i | (i, task) <- zip [0..] tasks]
  -- Wait for all tasks to complete
  return v

Is this guaranteed to be safe? Or do I need to have a mutex-like control (e.g. holding v in an MVar) to make sure that only one write proceeds at a time?

like image 646
Neil Brown Avatar asked Nov 14 '13 00:11

Neil Brown


1 Answers

From the code and the discussions in the comments, there seems to be no reason to assume it is not thread-safe. And just to support this, here is a little test for it:

import qualified Data.Vector.Mutable as V
import System.Environment
import Control.Concurrent.Async

thread v i 0 = return ()
thread v i n = do
    x <- V.read v i
    V.write v i $! x-1
    thread v i (n-1)

main = do
    [m,n] <- map read `fmap` getArgs
    v <- V.replicate m n
    tis <- mapM (\i -> async (thread v i n)) [0..m-1]
    mapM_ wait tis
    r <- mapM (V.read v) [0..m-1]
    if all (== 0) r then putStrLn "OK" else putStrLn $ "Not OK: " ++ show r

Here, even with 100 threads spawned in parallel, counting down from 1000000, with -RTS -N or -RTS -N10, always yields OK.

like image 106
Joachim Breitner Avatar answered Nov 05 '22 21:11

Joachim Breitner