2017-11-04 2 views
3

このコードHaskell Concurrent.Channel:この2つのコードの違いは何ですか?

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) 

は、後者のコードの出力は

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

である。しかし、前者の出力が唯一

ある

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) 

producerは、チャネルキューchに値を無期限に追加し、consumerは無制限にchの値をとることを意図していました。

後者のコードは私の意図と同じように機能しますが、前者のコードは機能しません。イベントログ(GHC-イベント)で

旧コード(forkIO $プロデューサーCH)が無期限に実行されないのはなぜ、ブロックはproducerスレッドでMVARに

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

を発生します。

答えて

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が返された後に存在を停止します。

関連する問題