如果从Java启动,子进程将忽略SIGQUIT

如果从Java启动,子进程将忽略SIGQUIT,java,linux,signals,Java,Linux,Signals,举个简单的例子: public class Main { public static void main(String[] args) throws Exception { Runtime.getRuntime().exec("sleep 1000"); // This is just so that the JVM does not exit Thread.sleep(1000 * 1000); } } 我使用open

举个简单的例子:

public class Main
{
    public static void main(String[] args) throws Exception
    {
        Runtime.getRuntime().exec("sleep 1000");

        // This is just so that the JVM does not exit
        Thread.sleep(1000 * 1000);
    }
}
我使用openjdk6在Linux上运行这个。如果我试图向“睡眠”进程发送一个
SIGQUIT
信号,它会忽略它。其他信号(
SIGINT
SIGTERM
等)都可以正常工作,但忽略了
SIGQUIT
。如果我只是在shell中运行
sleep 1000
,而不使用Java,那么
SIGQUIT
的处理是正确的


为什么行为不同?

-Xrs
选项传递给java。我已经测试了你的程序,有没有这个选项。如果没有该选项,SIGQUIT将被阻止;有了它,当我向它发送SIGQUIT信号时,信号不会被阻塞,睡眠过程也会终止

我能找到的关于发生了什么的最接近的解释在手册页中:

Sun的JVM捕获信号以实现异常JVM终止的关闭挂钩。JVM使用SIGHUP、SIGINT和SIGTERM来启动关机挂钩的运行

JVM使用类似的机制来实现1.2之前的特性,即转储线程堆栈以进行调试。Sun的JVM使用SIGQUIT执行线程转储

嵌入JVM的应用程序经常需要捕获信号,如SIGINT或SIGTERM,这可能会导致干扰JVM自己的信号处理程序。可以使用-Xrs命令行选项来解决此问题在Sun的JVM上使用-Xrs时,JVM不会更改SIGINT、SIGTERM、SIGHUP和SIGQUIT的信号掩码,也不会安装这些信号的信号处理程序。


我猜您必须为信号编写一个处理程序,以便您的程序实际上“退出”否。退出是
SIGQUIT
的默认操作。正如我在问题中所说的,如果我只是从shell运行命令而不使用Java,它会正确地处理
SIGQUIT
(=它退出),可能是因为sleep实际上实现了SIGQUIT的处理程序,这就是它实际上“退出”的原因。但是,当您从Java运行它时,您不是从shell运行它,这可能是不同之处。尝试
Runtime.getRuntime().exec(新字符串[]{”/bin/bash“,“-c”,“sleep 1000”})
并查看是否可以使用SIGQUIT终止该进程。@Edmundo:No。终止进程是
SIGQUIT
的默认操作。看:好的。看起来好像是
-Xrs
起了作用。但为什么会这样?即使JVM为SIGQUIT设置了一个信号处理程序,当通过
fork
+
exec
启动子进程时,也应该将其重置为默认操作,不是吗?我接受这个答案,但也基于这个问题发布了一个稍微不同的问题;请参阅:这看起来像是在对Runtime、ProcessBuilder、ProcessImpl和UNIXProcess进行一系列调用时,SIGQUIT被阻止并保持被阻止状态(被阻止的信号在fork和exec之间保持被阻止状态)。我还没有详细看过代码;在UNIXProcess中它没有被显式解除阻塞这一事实可能只是一个疏忽。这是有道理的。但是如果我尝试的话,它应该被解锁……这似乎不再有效。有什么解决办法吗?