2015-05-20 60 views
5

我正在嘗試使用通道/ STM來實現Haskell中的消息傳遞。也許這是一個可怕的想法,並且有更好的方式來實現/使用Haskell中的消息傳遞。如果是這樣,請讓我知道;然而,我的追求已經開啓了關於併發Haskell的一些基本問題。Haskell,通道,STM,線程,消息傳遞

我聽說過關於STM的偉大的事情,特別是在Haskell中的實現。既然它支持閱讀和寫作,並且有一些安全方面的好處,我想有人會從那裏開始。這帶來了我最大的一個疑問:

msg <- atomically $ readTChan chan 

其中瓚是TChan詮釋,導致等待是等待通道有它的價值?

考慮下面的程序:

p chan = do 
    atomically $ writeTChan chan 1 
    atomically $ writeTChan chan 2 

q chan = do 
    msg1 <- atomically $ readTChan chan 
    msg2 <- atomically $ readTChan chan 
    -- for testing purposes 
    putStrLn $ show msg1 
    putStrLn $ show msg2 

main = do 
    chan <- atomically $ newTChan 
    p chan 
    q chan 

與GHC --make -threaded編譯一下,然後運行該程序,而事實上你得到,隨後2打印到控制檯1。現在,假設我們做

main = do 
    chan <- atomically $ newTChan 
    forkIO $ p chan 
    forkIO $ q chan 

改爲。現在,如果我們使用 - 線程化,它或者不打印什麼,1或者1,然後是2打印到終端;然而,如果你不用-threaded編譯,它總是打印1,然後是2.問題2:-threaded和not之間有什麼區別?我認爲他們並不是真正的並行運行,而是一個接一個地運行。這與以下內容一致。

現在,我認爲如果我有p和q同時運行;即我forkio'd他們,他們應該能夠以相反的順序運行。假設

main = do 
    chan <- atomically newTChan 
    forkIO $ q chan 
    forkIO $ p chan 

現在,如果我編譯這個沒有-threaded,我從來沒有得到任何東西打印到控制檯。如果我用-thread進行編譯,我有時會這樣做。雖然,1和2之後很少 - 通常只有1或沒有。我也使用Control.Concurrent.Chan來測試,並獲得了一致的結果。

第二個大問題:渠道和叉子怎麼一起玩,以及上面的程序是怎麼回事?

無論如何,我似乎不能如此天真地模擬STM傳遞的消息。也許Cloud Haskell是解決這些問題的一個選項 - 我真的不知道。任何關於如何獲得消息傳遞的信息都不足以使用serialize ~~>寫入套接字~~>從套接字讀取~~>反序列化將非常感謝。

+0

重新工作:「什麼是-threaded與否的區別」,你可能會喜歡[我對Haskell的線程模型的闡述](http://dmwit.com/gtk2hs)。忽略gtk特定的位。 –

回答

8

沒有你的想法是正確的 - 這是kindof什麼TChan s爲的 - 你只是錯過了forkIO一個小點:

的問題是,你的主線程不會等待與創建的線程終止forkIOsee here for reference

,所以如果我使用提示在參考給定:

import Control.Concurrent 
import Control.Concurrent.STM 

p :: Num a => TChan a -> IO() 
p chan = do 
    atomically $ writeTChan chan 1 
    atomically $ writeTChan chan 2 

q chan = do 
    msg1 <- atomically $ readTChan chan 
    msg2 <- atomically $ readTChan chan 
    -- for testing purposes 
    putStrLn $ show msg1 
    putStrLn $ show msg2 

main :: IO() 
main = do 
    children <- newMVar [] 
    chan <- atomically $ newTChan 
    _ <- forkChild children $ p chan 
    _ <- forkChild children $ q chan 
    waitForChildren children 
    return() 

waitForChildren :: MVar [MVar()] -> IO() 
waitForChildren children = do 
    cs <- takeMVar children 
    case cs of 
    [] -> return() 
    m:ms -> do 
     putMVar children ms 
     takeMVar m 
     waitForChildren children 

forkChild :: MVar [MVar()] -> IO() -> IO ThreadId 
forkChild children io = do 
    mvar <- newEmptyMVar 
    childs <- takeMVar children 
    putMVar children (mvar:childs) 
    forkFinally io (\_ -> putMVar mvar()) 

它工作如預期S:

d:/Temp $ ghc --make -threaded tchan.hs 
[1 of 1] Compiling Main    (tchan.hs, tchan.o) 
Linking tchan.exe ... 
d:/Temp $ ./tchan.exe 
1 
2 
d:/Temp $ 

,當然它會繼續,如果您切換調用pq

+1

有沒有可以簡化這個'forkChild' /'waitForChildren'的東西的模塊/庫? – Bergi