views:

129

answers:

1

I am trying to understand concurrency in Haskell more deeply. I have the following code:

import Control.Concurrent
    main :: IO ()

    main = do 
    arr <- return $ [1..9]
    t <- newMVar 1
    forkIO (takeMVar t >> (print.show) arr >> putMVar t 1)
    forkIO (takeMVar t >> (print.show) arr >> putMVar t 1)
    forkIO (takeMVar t >> (print.show) arr >> putMVar t 1)
    forkIO (takeMVar t >> (print.show) arr >> putMVar t 1)
    forkIO (takeMVar t >> (print.show) arr >> putMVar t 1)
    return ()

Sometimes I see that the print operations overlap and I get the follow results (look at the second call):

*Main Control.Concurrent> :l test.hs 
[1 of 1] Compiling Main             ( test.hs, interpreted )
Ok, modules loaded: Main.
*Main Control.Concurrent> main
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
*Main Control.Concurrent> main
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
"[1,2,3,4,5,6,7,8,9]"
["[1,2,3,4,5,6,7,8,9]"
?"[1,2,3,4,5,6,7,8,9]"
1h*Main Control.Concurrent> 

I do not understand why this is happening. To use the MVar for [1..9] works bad too.

+4  A: 

Sometimes i see that the print operations overlaps

The output sometimes overlaps because there is a lock on standard output. Each thread calls "print", which attempts to write one character out, taking the lock for each character. Due to Haskell's preemptive concurrency, you will see random interleavings of threads printing.

If this is undesirable behavior, instead have each thread send the string it wishes printed to a printer thread, which in turn will do sequential line-by-line output.

Don Stewart
As i understand you haskell stdout print out the each character in separate thread ? Am i right ?
Anton