9

我一直在尝试ProcessProcessBuilder使用此 SSCCE。

        import java.io.IOException;
        public class TestProcess {
            public static void main(String[] args) {
                Process process = null;
                ProcessBuilder pb = new ProcessBuilder("notepad.exe");

                try {
                    process = pb.start();
                } catch (IOException e) {e.printStackTrace();}

                //have some time to close notepad
                try {
                    Thread.sleep(10*1000);
                } catch (InterruptedException ignored) {}

                try {
                    System.out.println(process.exitValue());
                 } catch (IllegalThreadStateException e) {
                    System.out.println(e);
                 }

                 if (process != null)
                     process.destroy();

                 /*try {
                     Thread.sleep(0, 1);
                 } catch (InterruptedException ignored) {}*/

                 System.out.println(process.exitValue());
             }
         }
  1. 如果我在 10 秒超时之前运行此代码并关闭记事本。destroy()尝试停止已终止的进程时调用未显示任何问题。为什么?
  2. 如果运行此代码并且根本不关闭记事本(带有注释的第二次睡眠)

似乎destroy是异步调用(只是发送一个信号?),这会导致第二个异常exitValue()

 java.lang.IllegalThreadStateException: process has not exited
 Exception in thread "main" java.lang.IllegalThreadStateException: process has not exited
        at java.lang.ProcessImpl.exitValue(ProcessImpl.java:246)
        at TestProcess.main(TestProcess.java:30)
  1. 如果我运行此代码并且根本不关闭记事本(带有未注释的第二次睡眠)exitValue,那么即使睡眠值只有 1 毫秒,第二次也不会抛出异常。是因为sleep()开销本身吗? 第二个exitValue将返回 1。

PS。我从 Windows 7 和 Eclipse 运行它。

4

3 回答 3

2

ProcessImpl.java关于destroy方法调用本机函数terminateProcess

public void destroy() { terminateProcess(handle); }

private static native void terminateProcess(long handle);

terminateProcess取决于平台,对于 Windows,您可以在此处找到源代码。它只是调用 Windows TerminateProcess 函数(该函数的链接在以前的答案中,或者你可以用谷歌搜索它)uExitCode=1- 这就是为什么销毁进程的退出代码是1.

在 linux 中看起来像是使用了类似的东西。并且作为证明下一个代码143在 ubuntu 中返回,对应于SIGTERMhttps://stackoverflow.com/a/4192488/3181901):

public static void main(final String[] args) throws IOException, InterruptedException {
    final Process process = Runtime.getRuntime().exec(args[0]);
    process.destroy();
    Thread.sleep(1000);
    System.out.println(process.exitValue());
}
于 2015-02-18T19:07:02.840 回答
1

我期待destroy() 方法正在调用本机Windows 函数TerminateProcess。查看MSDN,我发现了这一点:

TerminateProcess 是异步的;它启动终止并立即返回。如果您需要确保进程已终止,请使用进程句柄调用 WaitForSingleObject 函数。

所以我认为它解释了destroy确实是异步的。

同一来源的另一个摘录:

TerminateProcess 函数用于无条件地导致进程退出。

我想“无条件地”可以解释为什么在终止进程上调用 destroy() 不会失败。

希望这有帮助。(真的很有趣的问题!)

于 2012-12-20T13:17:13.360 回答
1
  1. 为什么显示问题?您正试图破坏一个已经被破坏的进程。的规范Process.destroy()并没有说明如果没有什么可以破坏会发生什么,所以假设如果没有什么可以破坏,那么就没有什么可抱怨的,这是合乎逻辑的(我想)。与Thread.join()相比,如果线程已经结束,它不仅会死掉。

  2. 杀死进程的唯一方法是向它发送信号。在某些操作系统上,还有其他更“暴力”的方式(例如,在某些平台上,可以简单地从操作系统的正在运行的进程列表中删除该进程。结果是未定义的,并且通常以丑陋的方式结束),但至少对于我所知道的平台,它实际上都是关于发送信号的。

  3. 实际上,可能是因为调用Thread.sleep(). 尝试增加超时值。

于 2012-12-20T13:17:30.167 回答