🎓 A1Learner
🔍
0 of 47 lessons completed

Haskell Chan and MVar

An MVar and a Chan are thread-safe boxes for handing values between threads. An MVar holds at most one value, while a Chan holds a queue of values.

One worker hands one value through an MVar

A worker puts 42 into an MVar. The main thread takes it and prints it.

import Control.Concurrent (forkIO, newEmptyMVar, putMVar, takeMVar)

main :: IO ()
main = do
  box <- newEmptyMVar
  _ <- forkIO $ putMVar box (42 :: Int)
  v <- takeMVar box
  print v

One producer hands three values through a Chan in order

A producer writes 1, 2, and 3 into a Chan. The main thread reads them in order.

import Control.Concurrent (forkIO, newChan, writeChan, readChan)

main :: IO ()
main = do
  ch <- newChan
  _ <- forkIO $ do
    writeChan ch (1 :: Int)
    writeChan ch 2
    writeChan ch 3
  a <- readChan ch
  b <- readChan ch
  c <- readChan ch
  print [a, b, c]

Two workers hand values through two MVars in a fixed order

One worker puts 10 into the first MVar and another puts 20 into the second. The main thread takes the first, then the second.

import Control.Concurrent (forkIO, newEmptyMVar, putMVar, takeMVar)

main :: IO ()
main = do
  boxA <- newEmptyMVar
  boxB <- newEmptyMVar
  _ <- forkIO $ putMVar boxA (10 :: Int)
  _ <- forkIO $ putMVar boxB (20 :: Int)
  a <- takeMVar boxA
  b <- takeMVar boxB
  print (a, b)

Example

import Control.Concurrent (forkIO, newChan, newEmptyMVar, putMVar, readChan, takeMVar, writeChan)

main :: IO ()
main = do
  ch <- newChan
  result <- newEmptyMVar
  _ <- forkIO $ do
    writeChan ch (10 :: Int)
    writeChan ch 20
    writeChan ch 30
  _ <- forkIO $ do
    a <- readChan ch
    b <- readChan ch
    c <- readChan ch
    putMVar result (a + b + c)
  total <- takeMVar result
  print total

Key points

  • MVar: an MVar holds at most one value and blocks a taker until a value arrives.
  • Chan: a Chan is an unbounded queue that keeps values in the order they were written.
  • PutMVar: putMVar places a value into an MVar.
  • TakeMVar: takeMVar takes a value from an MVar and blocks until one arrives.
  • WriteChan: writeChan adds a value to the end of a Chan queue.
  • ReadChan: readChan takes the oldest value from a Chan queue.

In this example, a producer thread writes 10, 20, and 30 into a Chan. A consumer thread reads all three values in order and adds them. The consumer puts the total into an MVar. The main thread takes the total and prints 60.

Note

the main thread takes results in a fixed order, so the printed order never depends on scheduling.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Haskell Playground

Exercise

What is the difference between an MVar and a Chan?