0

我在几个不同的 linux 机器(4+)上测试了这段代码(下面),它运行良好。但是,在一个 linux 机器上,我遇到了 readline() 因错误 inputStream(errorStream) 而挂起的问题。这个流应该是空的,所以我怀疑那个盒子没有为错误写出一个行终止符到errorStream。我将代码更改为使用 read() 而不是 readline() ...但 read() 也挂起。

我首先尝试检索输入 inputStream,并且工作正常,并且对于错误输入流,readline()/read() 没有挂起。我不能这样做,因为我需要先获取可能的错误。似乎是一个死锁,我能够通过让每个输入流从它自己的线程中读取来解决这个问题。为什么我只在一个盒子上看到这个问题?是否有内核设置或其他特定于此框的设置可能导致此问题?

   ProcessBuilder  processBuilder = new ProcessBuilder()
   try 
   {
       Process processA = null;
       synchronized (processBuilder)
       {
           processBuilder.command("/bin/sh","-c"," . /Home/SomeScript.ksh");
           processA = processBuilder.start();
       }

       inputStream = processA.getInputStream();
       reader = new BufferedReader(new InputStreamReader(inputStream));

       errorStream = processA.getErrorStream();
       errorReader = new BufferedReader(new InputStreamReader(errorStream));

       String driverError;

       while ((driverError = errorReader.readLine()) != null)
       {
           //some code
       }
4

2 回答 2

1

您正在脚本中运行特定于操作系统的命令,任何人都可能持有错误输出。您可以通过丢弃错误来避免这种情况,但这不太可能是一个好主意。

我会检查操作系统的版本是否相同,以及您在脚本中运行的命令是否有任何显着差异。如果这没有帮助,请从脚本中取出命令,直到它开始工作。我假设一个空脚本不会这样做。

于 2013-08-02T05:35:21.147 回答
1

为什么我只在一个盒子上看到这个问题?

很可能是因为正在运行的脚本中的某些内容......以及它与环境的交互(例如文件、环境变量等)

是否有内核设置或其他特定于此框的设置可能导致此问题?

它可能是内核设置,但不太可能。可能是“别的东西”。事实上,它必须是应该归咎于 Java 应用程序之外的“某些东西”,至少是部分原因。


我建议您暂时(至少)执行以下操作:

   ProcessBuilder  processBuilder = new ProcessBuilder();
   processBuilder.command("/bin/sh","-c"," . /Home/SomeScript.ksh");
   processBuilder.redirectErrorStream(true);

   processA = processBuilder.start();

   inputStream = processA.getInputStream();
   reader = new BufferedReader(new InputStreamReader(inputStream));
   String line;

   while ((line = reader.readLine()) != null) {
       System.out.println(line);
   }
   System.out.println("Return code is " + processA.exitValue());

这样你就可以看到所有的输出是什么。

如果外部进程未能在最后一行的末尾放置换行符,则应该没有问题。Java 进程将在输入流上看到一个 EOF,BufferedReader并将返回它具有的字符......并null在下一次调用时返回。


另一种可能性是外部进程正在阻塞,因为它试图从其标准输入中读取。


更新

redirectErrorStream 也解决了这个问题,但我需要单独的错误流。

好的,如果它确实(可靠地)解决了问题,那么(很可能)意味着您必须并行stdout读取外部进程和stderr流。简单的方法是创建 2 个线程来分别读取和缓冲两个流。例如:调用 Runtime.exec 时捕获标准输出

(您的问题是由于管道具有有限的缓冲能力。外部问题很可能在将内容写入stdout和之间交替出现stderr。如果它在管道“满”时尝试写入其中一个管道,它将阻塞. 但是如果你的应用程序在读取阻塞管道之前读取所有其他管道(到 EOF),那么一切都会死锁。外部进程卡在 PIPE_W 状态的事实更能证明这种解释。

您在不同系统上看到不同行为的一个可能原因是管道中的缓冲量取决于系统。但这也可能是由于外部流程所做的不同;例如它的输入。)

于 2013-08-02T06:00:11.413 回答