Java: closing std thread subprocesses?

from javadoc for java.lang.Process :

Process creation methods may not work well for special processes on some native platforms, such as embedded window processes, daemon processes, Win16 / DOS processes in Microsoft Windows, or shell scripts. The created subprocess does not have its own terminal or console. All its standard io operations (i.e., Stdin, stdout, stderr) will be redirected to the parent process through three streams (getOutputStream (), getInputStream (), getErrorStream ()). The parent process uses these threads to feed input and receive output from the subprocess. Since some proprietary platforms provide a limited buffer size for standard input and output streams, the inability to quickly write to the input stream or read the output stream of a subprocess can lead to blocking of the subprocess and even deadlock.

I know about this problem, and, of course, it makes sense to communicate with the subprocess in a timely manner if you want to communicate with it.

But what if you just want to start the process and don't care about I / O? In Java, is there a way to free resources in the parent process that are dedicated to managing the subprocess? (e.g. I / O channels and waiting for subprocess exit status)

If I do the following in the parent process:

  Process.getOutputStream().close(); Process.getInputStream().close(); Process.getErrorStream().close(); 

Do I still need to worry about a dead end? (for example, if the subprocess continuously sends data to its own stdout)

+3
source share
1 answer

You need to worry about two things:

  • Whether the process will block, trying to write to stdout, since you do not consume it, and
  • How does a process interpret threads closing?

Closing the output stream will not explicitly cause deadlocks if the process does not require input. However, the process will detect that the end of the thread has been reached, and may terminate accordingly. Take grep for example. This program will end when you close its input stream.

The easiest and safest way to ignore input will be to create a library that consumes and discards input in a separate stream. You've probably seen the Floating StreamGobbler class that does just that.

Edit

So, I tried the following with two different subprocess programs:

 Process proc = new ProcessBuilder(appStr).start(); proc.getInputStream().close(); InputStream eos = proc.getErrorStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(eos)); for ( String line = null; (line = reader.readLine()) != null; ) { System.err.println(line); } System.out.println(proc.waitFor()); 

The first time I wrote out a simple Java application:

 public class App { public static void main(String[] args) throws Exception { for ( int i = 0; i < 1000; i++ ) { System.out.println(i); } } } 

The process terminated normally, and the parent process completed displaying exit code 0 .

But then I tried to call it against the native program, in this case variations of cat , an echo of the file. In this case, the child process failed and wrote a garbled message to the error stream, complaining that the standard output stream was closed. It aborts abnormally with a nonzero exit code.

So really what you offer when closing threads will not be successful in the general case. You should know that a child process can gracefully handle output stream loss, and I suspect that most applications will not. My intuition is that Java can make a graceful crash when the output stream is closed, so from a software point of view the stream is still open, no one is listening.

+2
source

Source: https://habr.com/ru/post/897628/


All Articles