gpt4 book ai didi

Java、子进程和未读输出流 : When does it deadlock?

转载 作者:行者123 更新时间:2023-12-04 05:57:09 26 4
gpt4 key购买 nike

在 java 中使用 Runtime.exec() 创建子进程时,我知道我必须填充输入/排出输出流以防止子进程阻塞。

有趣的是,Process 的javadoc多说一点:

...failure to promptly write the input stream or read the output stream of
the subprocess may cause the subprocess to block, and even deadlock.

我想知道在这种情况下子进程可以 也是僵局 !

问题:
1. 什么情况下会死锁?
2. 为什么会死锁?
3. 你能提供一个简短的示例程序来显示这个死锁吗?
4. 这个死锁是操作系统的错误吗?

最佳答案

当父级在读取任何输出之前尝试向其子级的输入流发送太多数据时,由于缓冲区大小有限,可能会发生死锁。

考虑这个代码:

final int LINES = 10;
// "tr" is a Unix command that translates characters;
// Here, for every line it reads, it will output a line with
// every 'a' character converted to 'A'. But any command that outputs
// something for every line it reads (like 'cat') will work here
Process p = Runtime.getRuntime().exec("tr a A");
Writer out = new OutputStreamWriter(p.getOutputStream());
for (int i = 0; i < LINES; i++) {
out.write("abcdefghijklmnopqrstuvwxyz\n");
}
out.close();
// Read all the output from the process and write it to stdout
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}

对于 lines 的小值,它会正常工作;全部 tr的输出可以在我们开始读取它之前放入操作系统缓冲区。但是,对于较大的值(>10000 应该就足够了),操作系统缓冲区将被填满;内 tr命令,调用 write将阻塞,等待缓冲区被排空,反过来,Java 代码正在写入的缓冲区将填满(因为 tr 被阻塞,阻止它从其输入读取),进而阻塞我们的调用至 out.write ,导致死锁,两个进程都在等待写入未主动读取的完整缓冲区。

这种死锁不是操作系统中的错误,因为进程间通信的缓冲区大小有限是经过深思熟虑的设计决定。替代方案(无限缓冲区大小)有一些缺点:
  • 可以耗尽内核内存
  • 为避免上述情况,如果缓冲区自动“溢出”到磁盘,则可能导致不可预测的性能并可能填满磁盘。


  • 顺便说一句,由于进程内缓冲区也可能发生死锁。假设,为了尝试解决上述死锁,我们将 Java 代码更改为写入一行,然后交替读取一行。然而, it's common for Linux processes to not flush after every line when they're not writing directly to a terminal .所以 tr可能会读取一行,并将其写入其 libc 输出缓冲区,然后阻塞等待下一行写入——我们的 Java 代码将阻塞等待 tr输出一行。

    关于Java、子进程和未读输出流 : When does it deadlock?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9380466/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com