选择性发送TChan?

时间:2012-10-18 01:07:02

标签: multithreading haskell stm

AFAIK TChan充当集线器,发送的每条消息都被别人看到了吗?!
我想要一个TChan作为交换机向特定线程发送消息,并且还支持广播 有这样的事吗?

1 个答案:

答案 0 :(得分:3)

编辑:我重新阅读了你的问题。这个答案并没有完全解决“选择性发送”,尽管它澄清了TChan可以做什么。

下面描述的“广播”方法将唤醒所有听众(虽然从好的方面来看,每个项目不会制作1000份副本)。为避免这种情况,请使用Map方法作为@Mikhail建议。我是在chat server example中完成的。


TChan是一个FIFO队列:

  • writeTChan在最后添加一个项目。

  • readTChan从头开始读取项目。

例如,以下示例分叉10个线程,这些线程在单个通道上进行战斗:

import Control.Concurrent
import Control.Concurrent.STM
import Control.Monad

main = do
    chan <- newTChanIO

    forM_ [1..10] $ \i ->
        forkIO $
            forever $ do
                x <- atomically $ readTChan chan
                putStrLn $ "Thread " ++ show i ++ ": " ++ show x

    mapM_ (atomically . writeTChan chan) [1..1000]

    -- Wait for channel to empty out
    atomically $ do
        empty <- isEmptyTChan chan
        when (not empty) retry

这里,每个项目只由一个线程读取。

相比之下,以下示例通过使用dupTChan制作十个频道副本,将一个项目流“广播”到10个主题:

import Control.Concurrent
import Control.Concurrent.STM
import Control.Monad

main = do
    master <- newTChanIO

    forM_ [1..10] $ \i -> do
        chan <- atomically $ dupTChan master
        forkIO $
            forever $ do
                x <- atomically $ readTChan chan
                putStrLn $ "Thread " ++ show i ++ ": " ++ show x

    mapM_ (atomically . writeTChan master) [1..100]

    -- Give threads time to complete
    threadDelay 1000000

现在每个线程都会获取写入频道的所有项目。

需要注意的几个细微之处:

  • 写入dupTChan之前的频道的项目不会出现在新频道中。如果我们从子线程而不是主线程调用dupTChan,则可能首先发生一些writeTChan,这意味着孩子们可能看不到所有项目。

  • 由于没有人正在阅读master频道,因此写入该频道的内容会堆积起来,很可能不会被垃圾收集。要避免这种警告,请使用newBroadcastTChan创建master频道。