2

我正在开发一个完全用 Java 编写的大型系统。但在某些时候,我也会通过将 C 程序作为进程运行来与 C 程序通信,通过文件系统将一些输入传递给它,然后等待它完成从中读取结果。目前,除了这个,我什么都做不了。我没有时间通过​​ API 或类似的方式链接它们。

这工作得很好,直到我需要调用这个过程两次才能得到结果。我进行了第一次调用,它工作得很好。但是,对于第二次调用,该过程只是挂起!如果它正在睡觉并等待信号,我不知道,但我不明白为什么它应该这样做。

这是执行调用的方法:

public synchronized boolean processCommand(List command) {
    try { 
        ProcessBuilder pb = new ProcessBuilder(command);
        Process p = pb.start();
        p.waitFor();
        p.destroy();
    } catch(Exception ex) { return false; } 
    return true; 
}

我真的不需要与标准输出或标准输入通信。我只需要该过程运行并完成其工作。但是当调用进程仅在我第二次调用它时等待它时它就会挂起!我的调用代码只是简单地制作命令列表并从另一个 java 对象调用此方法。

当 C 程序的输入较小时,对方法 processCommand(List command) 的两次调用都可以正常工作。标准输入或标准输出会有问题吗?

简直快把我逼疯了!有人对此有见识吗?我很感激你的赞扬:)

更新:

这是基于@Gray提到的解决方案:

我只需要排空 InputStream 和可能的 ErrorStream:

public synchronized boolean processCommand(List command) {
try { 
    ProcessBuilder pb = new ProcessBuilder(command);
    Process p = pb.start();
    handleStream(p.getInputStream);
    handleStream(p.getErrorStream);
    p.waitFor();
    p.destroy();
} catch(Exception ex) { return false; } 
return true; 

}

public void handleStream(InputStream input) { 
    try { 
        int c; 
        while( (c=input.read())!= -1) { //Anything }
    } catch(Exception ex) { }
}
4

1 回答 1

1

尝试按照此处建议的解决方案进行操作(原始链接似乎不可用;可以在此处找到存档版本,尽管示例代码的引用链接仍指向原始站点...)

处理这种情况的最佳策略是在调用 waitFor 之前启动一个线程,这将在适当的时间段后中断当前线程。TimerTask 正是为这种情况而设计的,而 waitFor 在大多数情况下对中断非常敏感。[以原始链接为例]。

[...]

Java 6 API 明确指出,未能及时“读取子进程的输出流可能导致子进程阻塞,甚至死锁”。</p>

[...]

The safe bet for handling this problem today is to explicitly clean up every instance of Process by calling close on each stream made available through Process.getOutputSteam, Process.getInputStream, and Process.getErrorStream, and then call Process.destroy even if the process is already terminated.

于 2012-04-28T17:29:44.603 回答