
On Wed, Jan 11, 2012 at 10:28 PM, Erik de Castro Lopo
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.
My point is that the second runResourceT is not necessary.
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).
Actually, hsock is shared between both threads. With your original code, it gets closed regardless of what the other thread is doing. Which in this case is what you want, but you need to be careful.
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 [...]
What about inverting which thread gets to do what? _ <- resourceForkIO $ sourceHandle hsock $$ sinkHandle stdout sourceHandle stdin $$ sinkHandle hsock release releaseSock My reasoning is that: - 'sourceHandle stdin' will close after the user presses ^D, thereby reaching 'release releaseSock'. - After the socket is closed, 'sourceHandle hsock' will close as well, killing the thread. Note that without 'release releaseSock' the socket would not be closed until the other thread died.
[...] 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.
Actually, I'm not sure if my solution is better or worse than yours. The question is "how long does it take for the thread to die after hsock gets closed?" If the answer is "right away", then my solution is simpler =). Otherwise, you solution is less resource-hungry. Cheers, -- Felipe.