[Haskell-cafe] A simple telnet client using Conduit

Erik de Castro Lopo mle+hs at mega-nerd.com
Thu Jan 12 01:28:12 CET 2012

Thanks for the input Felipe.

Felipe Almeida Lessa wrote:

> On line 29, instead of
>   liftIO $ do
>     mapM_ ...
>     runResourceT $ do

Well that was because that whole block needs to run in IO.

> Regarding threads, you should use resourceForkIO [1] which has a quite
> nicer interface.

I did read about resourceForkIO and it says:

    Introduce a reference-counting scheme to allow a resource context to
    be shared by multiple threads. Once the last thread exits, all
    remaining resources will be released. 

In my case, I don't have any resources that are shared between threads.
All I have is the actual ThreadId returned by forkIO. Since that ThreadId
actually isn't used explicitly anywhere (but is implicitly passed to
killThread when "release releaseThread" is called).

The other thing about your solution is the question of what happens to
the ThreadId returned by resourceForkIO. Rewriting your solution to
explicity handle the ThreadId I get:

    telnet :: String -> Int -> IO ()
    telnet host port = runResourceT $ do
        (releaseSock, hsock) <- with (connectTo host $ PortNumber $ fromIntegral port) hClose
        liftIO $ mapM_ (\h -> hSetBuffering h LineBuffering) [ stdin, stdout, hsock ]
        tid <- resourceForkIO $ sourceHandle stdin $$ sinkHandle hsock
        sourceHandle hsock $$ sinkHandle stdout
        liftIO $ killThread tid
        release releaseSock

The problem here is that I am not sure if the explicit killThread is
actually needed and it is, I think my solution, where killThread happens
automatically is actually better. If what happens within the outer call
to resourceT is a long running process, your solution (in the absence of
the explicit killThread) could leave threads lying around that would
have been cleaned up much earlier in my soltuion.


Erik de Castro Lopo

More information about the Haskell-Cafe mailing list