Haskell forkIO threads writing on top of each other with putStrLn
Simply put, putStrLn
is not an atomic operation. Every character may be interleaved with any other from a different thread.
(I am also not sure about whether in multi-byte encodings such as UTF8 it is guaranteed that a multi-byte character is atomically handled.)
If you want atomicity, you can use a shared mutex e.g.
do lock <- newMVar ()
let atomicPutStrLn str = takeMVar lock >> putStrLn str >> putMVar lock ()
forkIO $ forever (atomicPutStrLn "hello")
forkIO $ forever (atomicPutStrLn "world")
As suggested in the comments below, we can also simplify and make the above exception-safe as follows:
do lock <- newMVar ()
let atomicPutStrLn str = withMVar lock (\_ -> putStrLn str)
forkIO $ forever (atomicPutStrLn "hello")
forkIO $ forever (atomicPutStrLn "world")