Haskell Concurrent.Channel:这两个代码有什么区别?

时间:2017-11-04 08:35:00

标签: haskell concurrency channel

为什么这段代码

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)

的行为方式不同
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)

后一个代码的输出是

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

但是,前者的输出只是

(0,0)

我打算producer无限期地向渠道队列ch添加值,而consumer无限期地从ch中获取值。

后一个代码的作用与我的内涵一样,但前一个代码没有。

在eventlog(ghc-events)中,阻塞发生在producer线程中的MVar上

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

为什么前一个代码(forkIO $ producer ch)不能无限期地运行。

1 个答案:

答案 0 :(得分:4)

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

  

在独立的GHC程序中,只有主线程需要终止才能使进程终止。因此,所有其他分叉线程将简单地与主线程同时终止(这种行为的术语是“守护线程”)。

     

如果您希望程序在退出前等待子线程完成,则需要自行编程。

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

  

[...]这告诉我们关于线程如何在Haskell中工作的重要事项:main返回时程序终止,即使还有其他线程仍在运行。其他线程只是停止运行,并在main返回后停止存在。