[Haskell-cafe] Re: getChar + System.Cmd.system + threads causes hangups

Simon Marlow simonmarhaskell at gmail.com
Tue Feb 21 10:22:04 EST 2006


Einar Karttunen wrote:
> Hello
> 
> Using system or any variant of it from System.Process
> seems broken in multithreaded environments. This
> example will fail with and without -threaded.
> 
> When run the program will print "hello: start" and
> then freeze. After pressing enter (the first getChar)
> System.Cmd.system will complete, but without that
> it will freeze for all eternity.
> 
> What is the best way to fix this? I could use System.Posix,
> but that would lose windows portablity which is needed.
> 
> import Control.Concurrent
> import System.Cmd
> 
> main = do forkIO (threadDelay 100000 >> hello)
>           getChar
>           getChar
> 
> hello = do putStrLn "hello: start"
>            system "echo hello world!"
>            putStrLn "hello: done"

The reason for the deadlock is because getChar is holding a lock on 
stdin, and System.Cmd.system needs to access the stdin Handle in order 
to know which file descriptor to dup as stdin in the child process (the 
stdin Handle isn't always FD 0, because of hDuplicateTo).

Maybe getChar shouldn't hold the lock while it is waiting.  I was 
vaguely aware of this when I wrote System.IO, but couldn't see an easy 
way to implement it, so currently all operations that block in I/O hold 
the Handle lock while they block.  Mostly this isn't a problem, but it 
does mean that things like hClose will block if there's another thread 
blocked in hGetChar on the same Handle (maybe you want it to cause the 
hGetChar to immediately fail instead).

One way to work around it in this case is to hDuplicate the standard 
Handles, and call runProcess passing your duplicate Handles.  I've just 
checked; this works fine.

import GHC.Handle (hDuplicate)

main = do
  i <- hDuplicate stdin
  o <- hDuplicate stdout
  e <- hDuplicate stderr
  forkIO (threadDelay 100000 >> hello i o e)
  getChar
  getChar

hello i o e = do
   putStrLn "hello: start"
   p <- runProcess "echo" ["hello world!"] Nothing Nothing (Just i) 
(Just o) (Just e)
   waitForProcess p
   putStrLn "hello: done"

Cheers,
	Simon


More information about the Haskell-Cafe mailing list