Concurrency: Threads and MVar
Compile with -threaded and run with +RTS -N to use multiple OS threads/cores.
MVar is a box that's either empty or full: takeMVar blocks when empty, putMVar blocks when full. It's a lock, a one-shot channel, and a synchronization primitive in one. It's prone to deadlocks when combined; prefer STM for composite state.
import Control.Concurrent
import Control.Monad
main :: IO ()
main = do
-- forkIO creates a lightweight (green) thread: you can create millions
done <- newEmptyMVar
_ <- forkIO $ do
forM_ [1 .. 3 :: Int] $ \i -> putStrLn ("worker: " ++ show i) >> threadDelay 100000 -- microseconds
putMVar done ()
putStrLn "main continues"
takeMVar done -- block until the worker signals
-- MVar as a lock-protected shared variable
counter <- newMVar (0 :: Int)
finished <- newEmptyMVar
forM_ [1 .. 10 :: Int] $ \_ -> forkIO $ do
replicateM_ 1000 (modifyMVar_ counter (pure . (+ 1)))
putMVar finished ()
replicateM_ 10 (takeMVar finished)
readMVar counter >>= print -- 10000
-- Channels
chan <- newChan
_ <- forkIO $ mapM_ (writeChan chan) [1 .. 5 :: Int]
replicateM 5 (readChan chan) >>= print