[Haskell-beginners] merge two handles

David McBride dmcbride at neondsl.com
Wed Jun 15 16:33:21 CEST 2011


The problem is the "forever" in the main thread.  It never has a way
to know that the two threads have died, but the stm knows that the
other two channels have disappeared, so they no longer block, and this
causes a busy loop.

So check this out.  I would have rather done it with a state monad to
count the number of threads I spawn and then wait for the appropriate
number of messages to arrive, but this way works too.

This is one of those cases where datatypes are awesome.  Now the
thread passes back either a line to be printed, or it tells the parent
thread that it has nothing left to print.  That way the main thread
knows exactly when to die.

Also, if you are going to be making command line scripts, I highly
recommend the cmdargs package on hackage, as it is pretty cool for
doing commandline arguments in a safe way.

{-# LANGUAGE ScopedTypeVariables #-}
module Main where

import GHC.Conc.Sync
import System.IO
import System.Environment
import System.Process
import Control.Monad
import Control.Concurrent.STM.TChan
import Control.Exception.Base
import Text.Printf
import Prelude hiding (catch)

data Message = MString String | ImDone

makeThread :: Handle -> TChan Message -> IO ThreadId
makeThread handle chan = forkIO $ (loop `catch` (\(e :: SomeException)
-> writeDone chan))
  where
    loop = do
      msg <- hGetLine handle
      writeMsg chan msg
      loop

    writeMsg chan msg = (atomically . writeTChan chan) $ MString msg
    writeDone chan = (atomically . writeTChan chan) ImDone

issueCmd :: String -> [String] -> IO ()
issueCmd cmd parms = do
    (_ ,Just hout ,Just herr ,_) <- createProcess (proc cmd parms) {
      std_out = CreatePipe,
      std_err = CreatePipe
    }
    chan <- newTChanIO :: IO (TChan Message)
    makeThread hout chan
    makeThread herr chan
    printCmd chan
    printCmd chan
  where
    printCmd chan = do
      msg <- atomically (readTChan chan)
      case msg of
        MString msg -> do
          putStrLn msg
          printCmd chan
        ImDone      -> return ()


main :: IO ()
main = do
 args <- getArgs
 let cmd = head args
 let parms = tail args
 issueCmd cmd parms
 print "Done"


On Wed, Jun 15, 2011 at 9:23 AM, Manfred Lotz <manfred.lotz at arcor.de> wrote:
> On Tue, 14 Jun 2011 13:10:36 -0400
> David McBride <dmcbride at neondsl.com> wrote:
>
>> It probably has to do more with parenthesis than anything:
>>
>> forever $ atomically $ readTchan chan >>= print
>> forever $ (atomically $ readTchan chan) >>= print
>>
>> That might work.  Once you get the types to line up, that should work.
>>
>
> Thanks for the hint. I finally got it compiled and almost working.
>
> The code is now like this:
>
>
> {-# LANGUAGE ScopedTypeVariables #-}
>
> import GHC.Conc.Sync
> import System.IO
> import System.Environment
> import System.Process
> import Control.Monad
> import Control.Concurrent.STM.TChan
> import Control.Exception.Base
> import Text.Printf
> import Prelude hiding (catch)
>
>
>
> makeThread :: Handle -> TChan String -> IO ThreadId
> makeThread handle chan = forkIO $
>  forever
>    (do eof <- hIsEOF handle
>        unless eof $ hGetLine handle >>= atomically . writeTChan chan)
>                            `catch` (\(e :: SomeException) -> return ())
>
> issueCmd :: String -> [String] -> IO ()
> issueCmd cmd parms = do
>  (_ ,Just hout ,Just herr ,_) <- createProcess (proc cmd parms) {
>    std_out = CreatePipe,
>    std_err = CreatePipe
>  }
>  chan <- newTChanIO :: IO (TChan String)
>  _ <- makeThread hout chan
>  _ <- makeThread herr chan
>  forever $ atomically (readTChan chan) >>= printf "%s\n"
>
> main :: IO ()
> main = do
>  args <- getArgs
>  let cmd = head args
>  let parms = tail args
>  issueCmd cmd parms
>  print "Done"
>
>
>
> If I run this with a command the command's output will be printed but
> after that the program is hanging, and top shows 100% cpu usage. "Done"
> will never be printed.
>
> Any idea what I have to add to prevent it from hanging?
>
>
> --
> Thanks,
> Manfred
>
>
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>



More information about the Beginners mailing list