[Haskell-cafe] Re: getChar + System.Cmd.system + threads causes
simonmarhaskell at gmail.com
Tue Feb 21 10:22:04 EST 2006
Einar Karttunen wrote:
> 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)
> 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)
hello i o e = do
putStrLn "hello: start"
p <- runProcess "echo" ["hello world!"] Nothing Nothing (Just i)
(Just o) (Just e)
putStrLn "hello: done"
More information about the Haskell-Cafe