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 resultA 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 secondExample
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?