3

Java 中通过 Runtime.exec 创建子进程时,父子进程管道通信问题

 2 years ago
source link: https://www.v2ex.com/t/855368
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

V2EX  ›  Java

Java 中通过 Runtime.exec 创建子进程时,父子进程管道通信问题

  linuxsteam · 7 小时 26 分钟前 · 622 次点击

小弟最近在研究父子进程中如何用管道进行通信,但是遇到一个情况,目前无法理解现有的答案。

shell 脚本

#!/bin/bash

for((i=0; i<10913; i++));do
    # 输出到 stdin
    echo "input"
    # 输出到 stderr
    echo "error" 1>&2
done
public static Object executeCommand(String command) throws Exception
    {
        ProcessBuilder processBuilder = new ProcessBuilder(command);
        Process process = processBuilder.start();
        readStreamInfo(process.getInputStream(), process.getErrorStream());
        int exit = process.waitFor();
        process.destroy();
        if (exit == 0)
        {
            System.out.println("子进程正常完成");
        }
        else
        {
            System.out.println("子进程异常结束");
        }
        return null;
    }

    private static void readStreamInfo(InputStream... inputStreams){
        try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStreams[0]),8192))
        {
            String line;
            int i = 0;
            while (true)
            {
                String s = br.readLine();
                if (s != null)
                {
                    System.out.println(++i + " " + s);
                }
                else
                {
                    break;
                }
            }
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
        finally
        {
            try
            {
                inputStreams[0].close();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }


        try (BufferedReader bufferedInput = new BufferedReader(new InputStreamReader(inputStreams[1])))
        {
            String line;
            int i = 0;
            while ((line = bufferedInput.readLine()) != null)
            {
                System.out.println(++i + " " + line);
            }
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
        finally
        {
            try
            {
                inputStreams[1].close();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

实测断点会卡在 String s = br.readLine();迟迟没有收到返回值。

shell 中 for 循环减少一次错误流输出上述代码就不会阻塞。

所以我参考网上搜索结果和查阅书籍下了个结论:

以上问题是缓冲区满了导致的

但是还是有几个问题不能理解,希望有研究过的大佬可以帮帮小弟。

  • 以上方式产生的父子进程标准 I/O 流的对应关系是下列我理解的哪一种?
    1. 子进程的标准输出流,标准错误流重定向到父进程的标准输入流。(共用一个管道)
    2. 子进程的标准输出流重定向到父进程的标准输入流,子进程的标准错误流重定向到父进程的标准错误流。(各自一个管道)
  • 我的代码为什么会阻塞? 我就在 shell 中只写了一行标准输出,标准输入流已经读完了,为何会卡主。不应该直接返回 null 跳出循环吗?(在 InputStream.readLine()中看到了 EOF 相关字样,以为是没有读到 EOF 描述才卡死的。但是减少错误输出条数不会阻塞这个事实,让我放弃了这个理解)
  • 哪本书对于以上问题有所讲解。(我查了两本操作系统的书,感觉还是不能帮我理解以上问题)

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK