🎓 A1Learner
🔍
0 of 47 lessons completed

Haskell Project Concurrent Processor

A concurrent processor is a program that splits work across threads and gathers the results in a fixed order. The main thread takes exactly what each worker puts, so the output never depends on scheduling.

An MVar rendezvous returns one worker result

The worker puts one number into the box. 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)
  result <- takeMVar box
  print result

A Chan returns queued values in order

The worker writes three numbers into the queue. The main thread reads them in the same order.

import Control.Concurrent (Chan, forkIO, newChan, readChan, writeChan)
worker :: Chan Int -> IO ()
worker ch = do
  writeChan ch 10
  writeChan ch 20
  writeChan ch 30
main :: IO ()
main = do
  ch <- newChan
  _ <- forkIO (worker ch)
  a <- readChan ch
  b <- readChan ch
  c <- readChan ch
  print [a, b, c]

A TVar update reads back inside the main thread

The TVar starts at 10 and gains 5 in a transaction. A second transaction then doubles it.

import Control.Concurrent.STM (atomically, modifyTVar', newTVarIO, readTVarIO)
main :: IO ()
main = do
  box <- newTVarIO 10
  atomically (modifyTVar' box (+5))
  first <- readTVarIO box
  print first
  atomically (modifyTVar' box (*2))
  second <- readTVarIO box
  print second

Example

import Control.Concurrent (MVar, forkIO, newEmptyMVar, putMVar, takeMVar)
worker :: [Int] -> MVar Int -> IO ()
worker xs box = putMVar box (sum xs)
main :: IO ()
main = do
  box1 <- newEmptyMVar
  box2 <- newEmptyMVar
  _ <- forkIO (worker [1..5] box1)
  _ <- forkIO (worker [6..10] box2)
  a <- takeMVar box1
  b <- takeMVar box2
  print [a, b]
  print (a + b)

Key points

  • Concurrent processor: a program that splits work across threads and gathers results in a fixed order.
  • MVar: a box that holds at most one value and blocks a taker until a value arrives.
  • Chan: an unbounded queue that threads can write to and read from in order.
  • TVar: a changeable box shared between threads inside software transactional memory.
  • Rendezvous: the main thread taking exactly what workers put, in a fixed order.

In this example, the program starts two workers, one summing the numbers from 1 to 5 and one summing the numbers from 6 to 10, then the main thread takes the first result and then the second result, prints both, and prints their total.

Note

no thread prints on its own here, so the output order is fixed by the takes in the main thread.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Haskell Playground

Exercise

What makes the processor output deterministic?