Re: a question about using ProcessBuilder to call external command
On 3/12/2014 4:06 PM, zyng wrote:
Hi:
I am using the following code to call a system command
final ProcessBuilder processBuilder = new ProcessBuilder(new String[]{"/bin/sh", "-c", the_command_and_arguments});
final Process processRunSysCmd = processBuilder.start();//start a new process -- a child process
I have learned that I need to drain the output of the external command (input stream to the parent process -- the java program) in case that it has too much output and the buffer is saturated. In that case, the program will hang.
The details vary from one operating system to another, but yes:
The amount of output that can be held "in transit" waiting to be read
is usually limited, and may be rather small. If the writing process
fills that output buffer faster than the reading process drains it,
the writer will eventually need to wait for the reader to make some
progress. And if the reader's progress rate is zero, the writer may
need to wait for a v-e-r-y l-o-n-g t-i-m-e.
But when I think deeper, I am puzzled: there are two processes running now(one is the one i called "parent process", another is the child process). Since each one is single threaded, may I say there are two threads right now?!
Yes, or better "At least three, and probably more." The parent
process, written in Java and running on the JVM, is almost certainly
*not* single-threaded (think garbage collector threads, finalizer
threads, ...) But even if the JVM were single-threaded, you'd then
have a child process running "/bin/sh" (at least one thread) and
probably a grandchild process running "the_command_and_arguments"
(at least one thread), and maybe great-grandchildren and further
descendants.
So if I don't drain the output of the child process, and too much output and buffer saturated, the parent process will hang?! Will the child process hang too? Or both processes hang? Since they are two threads, so one thread cause another thread hang?
I think you've got it backwards: The *writer* will hang when its
buffer fills, but the *reader* isn't impeded. For all the system
knows, the (non-)reader may be doing some housekeeping before getting
ready to read what the writer wrote.
If you don't care about the output from the child/grandchild/...
processes, an alternative to draining and discarding it may be to
have it written to a sinkhole destination like "/dev/null" instead
of to a pipe or socket or other IPC channel.
--
Eric Sosman
esosman@comcast-dot-net.invalid