java:关闭子进程标准流?

Posted

技术标签:

【中文标题】java:关闭子进程标准流?【英文标题】:java: closing subprocess std streams? 【发布时间】:2011-08-08 20:40:00 【问题描述】:

来自java.lang.Process的javadoc:

创建进程的方法可能不适用于某些本机平台上的特殊进程,例如本机窗口进程、守护进程、Microsoft Windows 上的 Win16/DOS 进程或 shell 脚本。创建的子进程没有自己的终端或控制台。它所有的标准io(即stdin、stdout、stderr)操作都会通过三个流(getOutputStream()、getInputStream()、getErrorStream())重定向到父进程。父进程使用这些流向子进程提供输入并从子进程获取输出。由于一些原生平台只为标准输入输出流提供有限的缓冲区大小,未能及时写入子进程的输入流或读取输出流可能会导致子进程阻塞,甚至死锁。

我知道这个问题,当然,如果您想与子进程进行通信,及时与它进行通信是有意义的。

但是,如果您只想启动一个进程而不关心 I/O,该怎么办?在 Java 中,有没有办法释放父进程中专门用于管理子进程的资源? (例如 I/O 管道和等待子进程退出状态)

如果我在父进程中执行以下操作:

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

我还需要担心死锁吗? (例如,如果子进程不断将数据发送到自己的标准输出)

【问题讨论】:

【参考方案1】:

您需要担心两件事:

    进程是否会阻塞,尝试写入标准输出,因为您无法使用它,并且 进程将如何解释正在关闭的流?

除非进程需要输入,否则关闭输出流显然不会导致死锁。但是,进程检测到流的末尾已经到达,并可能相应地终止。以grep 为例。该程序将在您关闭其输入流时终止。

忽略输入的最简单和最安全的方法是创建一个库,在单独的线程上使用和丢弃输入。您可能已经看到了 StreamGobbler 类浮动,它就是这样做的。

编辑

所以我尝试了以下两个不同的子进程程序:

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());

第一次,我调用了一个简单的 Java 应用程序:

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

进程正常结束,父进程终止并显示0 退出代码。

但后来我尝试针对本机程序调用它,在本例中为 cat 变体,回显文件。在这种情况下,子进程失败并向错误流写入一条乱码消息,抱怨标准输出流已关闭。它以非零退出代码异常终止。

因此,在一般情况下,您关闭流的建议确实不会成功。您必须知道子进程可以优雅地处理丢失其输出流,我怀疑大多数应用程序不会。我的直觉是,当输出流关闭时,Java 可以做一些优雅的失败,这样从程序的角度来看,流仍然是打开的,没有人在听。

【讨论】:

“忽略输入的最简单和最安全的方法是创建一个库,在单独的线程上使用和丢弃输入”——我同意,我只是不想使用更多资源除非我必须这样做,否则生成子进程。我只想让子流程去做自己的事情。 (在此处插入疏忽育儿类比) @Jason:我做了更多测试,并在上面包含了我的发现。 好的,很酷,非常感谢。在我短期内担心的情况下,它是一个启动第二个 JVM 的 JVM,所以听起来它可以正常工作(或者至少关闭会比不处理 stdout/stderr 流更好)跨度>

以上是关于java:关闭子进程标准流?的主要内容,如果未能解决你的问题,请参考以下文章

在 Rust 中写入子进程的标准输入?

从Java开始忽略/捕获子进程输出的最简单方法

Python标准库06 子进程 (subprocess包)

关闭其它进程占用的文件句柄

Python中的子进程是啥? [关闭]

node.js python子进程不会实时打印