Threads are subroutines that can run concurrently. Every Haskell program begins with one thread, called the main thread. Starting an additional thread is called forking a thread.
To fork a thread, use the
forkIO function from the
import Control.Concurrent (forkIO) import Control.Concurrent.STM.TVar import Control.Monad.STM import Data.Foldable (for_) import System.IO
= main do
Setting the output stream’s buffer mode to line-buffering will make the output of this example more readable.
LineBuffering hSetBuffering stdout <- atomically (newTVar 0) tasksCompleted
We define a function called
= task x do
- Prints three times; then
1..3] $ \i -> for_ [putStrLn (x ++ ": " ++ show i)
- Increments the
$ atomically + 1) modifyTVar' tasksCompleted (
task three times: Once in the main thread, and then twice in new forked threads.
"main" task "forkA") forkIO (task "forkB") forkIO (task
At this point, our two forked threads are now running, and we do not want the main thread to end (thus terminating the program) before the other threads have time to finish. So we wait until the value of
tasksCompleted reaches 3.
$ atomically do <- readTVar tasksCompleted x == 3) check (x putStrLn "done"
$ runhaskell threads.hs
The lines from
task "main" are printed first; no fork has occurred yet.
main: 1 main: 2main: 3
task "forkA" and
task "forkB" run concurrently, their
putStrLn effects are interleaved.
forkA: 1 forkB: 1 forkA: 2 forkB: 2 forkA: 3 forkB: 3done
The interleaving is nondeterministic; if you run this program multiple times, you may see different orderings.
$ runhaskell threads.hs main: 1 main: 2 main: 3 forkA: 1 forkB: 1 forkB: 2 forkB: 3 forkA: 2 forkA: 3done