2015-05-20 57 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