linux 了解I/O阻塞

inb24sb2  于 2023-02-03  发布在  Linux
关注(0)|答案(3)|浏览(171)

我有一个二进制linux可执行文件,它在stdout中打印一些字节。我从Java应用程序中使用这些字节,如下所示:

String[] cmd;
Process p = Runtime.getRuntime().exec(cmd);
InputStream is = p.getInputStream();
int r = is.read();
while(r != -1){
    System.out.println(r);
    r = is.read(); //1
}

但是在工作了一段时间之后,//1被永远阻塞了I/O(死锁)。

"pool-2-thread-1@627" prio=5 tid=0xd nid=NA runnable
  java.lang.Thread.State: RUNNABLE
      at java.io.FileInputStream.readBytes(FileInputStream.java:-1)
      at java.io.FileInputStream.read(FileInputStream.java:255)
      at java.io.BufferedInputStream.read1(BufferedInputStream.java:284)
      at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
      - locked <0x2c0> (a java.lang.UNIXProcess$ProcessPipeInputStream)
      at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
      at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
      at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)

它锁定在本机方法上

private native int readBytes(byte[] var1, int var2, int var3) throws IOException;

这个方法被永远阻止的可能原因是什么?也许这是特定于平台的。我使用的是Ubuntu 16.04

jutyujz0

jutyujz01#

您不需要查看标准库的内部方法来获得答案,InputStream.read()的文档部分地说明了
如果由于已到达流的结尾而没有字节可用,则返回值-1。此方法将一直阻塞,直到输入数据可用、检测到流的结尾或引发异常。
也许混淆的关键点是“检测到流的结尾”的含义。这 * 并不 * 意味着现在没有更多的字节可供读取--这将与方法阻塞直到数据可用的规范不一致,并且在实践中,它在许多情况下的效果很差。当系统接收到某种表示不再有字节可从流中获得的信号时,检测到流的结束。通常,这意味着流在源端已被关闭,并且在目的地端从流中排出所有字节。
在您的特定情况下,如果外部进程保持运行,不向其标准输出进一步写入任何内容,但不 * 关闭 * 其标准输出,则Java(或本机使用者)将永远不会在该进程的输出上看到流结束。

pokxtpni

pokxtpni2#

您的InputStream正在等待进程提供另一个字节,或者关闭流(通过完成)。
进程可能不执行这两项操作的一个原因是,它被写入stderr,并且在该写入时阻塞。
您的shell和Java使用的环境之间可能存在差异,这意味着命令将导致输出到stderr(例如,程序不在$PATH中;您没有足够的权限;您的CWD不是您所期望的,等等。)
一种快速而粗略的方法是将stderr重定向到stdout--或者使用ProcessBuilder.redirectErrorStream(),或者在UNIX端使用2>&1

  • 如果 * 是这种情况,那么它 * 就是 * 死锁的一种形式--Java程序正在等待本机程序写入一个管道,而本机程序正在等待Java程序从另一个管道读取数据。

从长远来看,处理它的干净方法是使用getErrorStream()并处理它的输出。这并不是微不足道的,因为在使用阻塞读取的单线程程序中,您永远不知道哪个流将具有数据。您可以在单独的线程中执行阻塞读取,或者使用NIO以非阻塞方式处理两个输入。
顺便说一句,请注意,从Java 1.5开始,Java文档建议ProcessBuilder.start()优于Runtime.exec()

58wvjzkj

58wvjzkj3#

Linux下有five different type IO model,分别是

  • 阻塞IO
  • 非阻塞IO
  • IO多路复用
  • 信号驱动
  • 非同步信号IO

java.io.FileInputStream.readBytes()使用第一种类型,阻塞IO。应用程序等待内核返回数据。

相关问题