2017-11-04 3 views
3

Warum dieser CodeHaskell Concurrent.Channel: Was ist der Unterschied zwischen diesen beiden Codes?

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) 

nicht die gleiche Weise verhält sich wie

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) 

Der Ausgang des letzteren Code

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

Aber der ehemalige jemandes Ausgang ist nur

ist
(0,0) 

Ich beabsichtigte, dass producer unbegrenzt einen Wert der Kanalwarteschlange hinzufügen ch, und consumer unbegrenzt einen Wert von ch nehmen.

Der letztere Code funktioniert so gut wie meine Absicht, aber der ehemalige nicht.

In den eventlog (GHC-Ereignisse), geschieht Block auf einem MVar in producer Gewinde

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

Warum der ehemalige Code (forkIO $ Produzent ch) laufen nicht auf unbestimmte Zeit nicht.

Antwort

4

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

In einem Standalone-Programm GHC, nur der Hauptfaden für den Prozess zu beenden, um erforderlich zu beenden. Somit werden alle anderen gegabelten Threads einfach gleichzeitig mit dem Haupt-Thread beendet (die Terminologie für diese Art von Verhalten ist "dämonische Threads").

Wenn Sie möchten, dass das Programm darauf wartet, dass untergeordnete Threads beendet werden, bevor sie beendet werden, müssen Sie dies selbst programmieren.

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

[...] Das sagt uns etwas Wichtiges über, wie Threads arbeiten in Haskell: das Programm beendet, wenn main zurückkehrt, auch wenn es noch andere Threads läuft. Die anderen Threads hören einfach auf zu laufen und hören auf zu existieren, nachdem main zurückkehrt.

Verwandte Themen