
Since some people on IRC asked for an example implementation, two implementations spring to mind:
Implementation #1:
newBroadcastChan :: IO (Chan a)
newBroadcastChan = do
hole <- newEmptyMVar
readVar <- newMVar (error "reading from a TChan created by newBroadcastTChan; use dupTChan first")
writeVar <- newMVar hole
return (Chan readVar writeVar)
Pros:
- Identical to TChan equivalent
- Only one extra function to the API
Cons:
- Accidental reads lead to crash
Implementation #2:
newtype BroadcastChan a = BChan (MVar (Stream a))
newBroadcastChan :: IO (BroadcastChan a)
newBroadcastChan = do
hole <- newEmptyMVar
writeVar <- newMVar hole
return (BChan writeVar)
dupFromBroadcastChan :: BroadcastChan a -> IO (Chan a)
dupFromBroadcastChan (BChan writeVar) = do
hole <- readMVar writeVar
newReadVar <- newMVar hole
return (Chan newReadVar writeVar)
Pros
- Prevents accidental reads from write-only Chan
Cons
- Adds more new stuff to that API?
Cheers,
Merijn
On 09 Sep 2014, at 00:30 , Merijn Verstraaten
Ola!
Control.Concurrent.STM.TChan has the “newBroadcastTChan :: STM (TChan a)”, this creates a “write-only” TChan to avoid any space leaks when a Chan is written too but never read from (for example, when dupTChan is used to hand a copy to threads). Unfortunately, no such variant seems to exist for the normal Chan? I have the following code:
foo :: Chan a -> IO Foo foo broadcast = do newListener <- dupChan broadcast forkIO $ doStuffWith newListener
This means the original Chan is never read from and much like the problem with TChan, values keep piling up in the original channel, causing a space leak. I propose adding
newBroadcastChan :: IO (Chan a)
The obvious Chan equivalent of newBroadcastTChan, which creates a write-only channel without read end, thus avoiding this space leak.
Discussion: 2 weeks?
Cheers, Merijn