小弟最近在研究父子进程中如何用管道进行通信,但是遇到一个情况,目前无法理解现有的答案。
代码复现
shell 脚本
#!/bin/bash
for((i=0; i<10913; i++));do
# 输出到 stdin
echo "input"
# 输出到 stderr
echo "error" 1>&2
done
java
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 流的对应关系是下列我理解的哪一种?
- 子进程的标准输出流,标准错误流重定向到父进程的标准输入流。(共用一个管道)
- 子进程的标准输出流重定向到父进程的标准输入流,子进程的标准错误流重定向到父进程的标准错误流。(各自一个管道)
- 我的代码为什么会阻塞? 我就在 shell 中只写了一行标准输出,标准输入流已经读完了,为何会卡主。不应该直接返回 null 跳出循环吗?(在 InputStream.readLine()中看到了 EOF 相关字样,以为是没有读到 EOF 描述才卡死的。但是减少错误输出条数不会阻塞这个事实,让我放弃了这个理解)
- 哪本书对于以上问题有所讲解。(我查了两本操作系统的书,感觉还是不能帮我理解以上问题)