为什么这段代码
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)不能无限期地运行。
答案 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
返回后停止存在。