Why does process hang if the parent does not consume stdout/stderr in Java?
Asked Answered
H

2

14

I know that if you use ProcessBuilder.start in Java to start an external process you have to consume its stdout/stderr (e.g. see here). Otherwise the external process hangs on start.

My question is why it works this way. My guess is that JVM redirects stdout/stderr of the executed process to pipes and if the pipes have no room the writes to the pipes block. Does it make sense?

Now I wonder why Java does it way. What is the rationale behind this design?

Humdinger answered 7/6, 2013 at 11:46 Comment(3)
What else should be done? Should the streams be simply ignored? This way the caller is forced to read the streams.Hartford
Like @UwePlonus said; if you really wish to ignore them all, just create some kind of DevNull{Input,Output}Stream or something (the JVM may even have that already, I don't know)Gabrielson
BTW, the exact same thing will happen at the Unix command line if you redirect std{out,err} to a named pipe and don't read from it.Gabrielson
E
14

Java doesn't do anything in this area. It just uses OS services to create the pipes.

All Unix like OSs and Windows behave the same in this regard: A pipe with a 4K is created between parent and child. When that pipe is full (because one side isn't reading), the writing process blocks.

This is the standard since the inception of pipes. There is not much Java can do.

What you can argue is that the process API in Java is clumsy and doesn't have good defaults like simply connecting child streams to the same stdin/stdout as the parent unless the developer overrides them with something specific.

I think there are two reasons for the current API. First of all, the Java developers (i.e. the guys at Sun/Oracle) know exactly how the process API works and what you need to do. They know so much that it didn't occur to them that the API could be confusing.

The second reason is that there is no good default that will work for the majority. You can't really connect stdin of the parent and the child; if you type something on the console, to which process should the input go?

Similarly, if you connect stdout, the output will go somewhere. If you have a web app, there might be no console or the output might go somewhere where no one will expect it.

You can't even throw an exception when the pipe is full since that can happen during the normal operation as well.

Encephalography answered 7/6, 2013 at 11:58 Comment(1)
Sir, do we need two external threads to read both inputStream and errorStream of ProcessBuilder and execute this before calling waitFor()?Homey
M
9

It is explained in the javadoc of Process:

By default, the created subprocess does not have its own terminal or console. All its standard I/O (i.e. stdin, stdout, stderr) operations will be redirected to the parent process, where they can be accessed via the streams obtained using the methods getOutputStream(), getInputStream(), and getErrorStream(). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock.

Mick answered 7/6, 2013 at 11:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.