Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Concurrent.Channel: What is difference between this two codes?

Why this code

import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TChan

main = do
  ch <- newTChanIO
  forkIO $ consumer ch 0
  forkIO $ consumer ch 1
  ----------------------
  forkIO $ producer ch
  ----------------------
  return ()


producer ch = loop 0
  where
    loop n = do
      atomically $ writeTChan ch n
      threadDelay (10^5 :: Int)
      loop (n+1)


consumer ch n = forever $ do
  v <- atomically $ readTChan ch
  print (n, v)

doesn't behave the same way as

import Control.Monad
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TChan

main = do
  ch <- newTChanIO
  forkIO $ consumer ch 0
  forkIO $ consumer ch 1
  ----------------------
  producer ch
  ----------------------
  return ()


producer ch = loop 0
  where
    loop n = do
      atomically $ writeTChan ch n
      threadDelay (10^5 :: Int)
      loop (n+1)


consumer ch n = forever $ do
  v <- atomically $ readTChan ch
  print (n, v)

The latter code's output is

(0,0)
(1,1)
(1,2)
(1,3)
(1,4)
(0,5)
(0,6)
(1,7)
...

But, the former one's output is only

(0,0)

I intended that producer indefinitely add a value to the channel queue ch, and consumer indefinitely take a value from ch.

The latter code acts as well as my intension, but the former one doesn't.

In the eventlog (ghc-events), block happens on an MVar in producer thread

4775372: cap 0: stopping thread 8 (blocked on an MVar)

Why the former code (forkIO $ producer ch) doesn't indefinitely run.

like image 232
oky Avatar asked Feb 28 '26 15:02

oky


1 Answers

http://hackage.haskell.org/package/base-4.10.0.0/docs/Control-Concurrent.html#g:12:

In a standalone GHC program, only the main thread is required to terminate in order for the process to terminate. Thus all other forked threads will simply terminate at the same time as the main thread (the terminology for this kind of behaviour is "daemonic threads").

If you want the program to wait for child threads to finish before exiting, you need to program this yourself.

http://chimera.labs.oreilly.com/books/1230000000929/ch07.html#sec_reminders:

[...] This tells us something important about how threads work in Haskell: the program terminates when main returns, even if there are other threads still running. The other threads simply stop running and cease to exist after main returns.

like image 138
melpomene Avatar answered Mar 02 '26 04:03

melpomene