我应该以什么顺序发送信号以正常关闭进程?

时间:2009-03-27 16:17:23

标签: bash signals job-control sigterm

在另一位commentthis answer question上,评论者说:

  

除非绝对,否则不要使用kill -9   必要! SIGKILL不能被困   被杀死的程序无法运行任何   例如关闭例程抹去   临时文件。首先尝试HUP(1),   然后是INT(2),然后是QUIT(3)

我原则上同意SIGKILL,但其余的对我来说都是新闻。鉴于kill发送的默认信号是SIGTERM,我认为这是任意进程正常关闭的最常见信号。此外,我已经看到SIGHUP用于非终止原因,例如告诉守护程序“重新读取您的配置文件”。而且在我看来SIGINT(你通常用Ctrl-C得到的中断,对吗?)并没有得到应有的广泛支持,或者相当不理想地终止。

鉴于SIGKILL是最后的手段 - 您应该向任意进程发送哪些信号以及按什么顺序,以便尽可能优雅地关闭它? / p>

如果可以,请用支持事实(超出个人喜好或意见)或参考资料来证实您的答案。

注意:我对包括考虑bash / Cygwin的最佳实践特别感兴趣。

编辑:到目前为止,似乎没有人提到INT或QUIT,而且HUP的提及也很有限。有没有理由将这些包括在有序的过程中?

7 个答案:

答案 0 :(得分:97)

SIGTERM告诉应用程序终止。其他信号告诉应用程序其他与关闭无关但可能有相同结果的事情。不要使用那些。如果您希望关闭应用程序,请告诉它。不要给它误导信号。

有些人认为终止进程的智能标准方法是向其发送大量信号,例如HUP,INT,TERM,最后是KILL。这是荒唐的。终止的正确信号是SIGTERM,如果SIGTERM没有立即终止该过程,那么这是因为应用程序选择处理信号。这意味着它有一个很好的理由不立即终止:它有清理工作要做。如果你用其他信号中断清理工作,就不知道它还没有保存到磁盘中的内存中的哪些数据,哪些客户端应用程序处于挂起状态,或者你是否正在“中等句子”中断它,这实际上是数据损坏。

有关信号真正含义的更多信息,请参阅sigaction(2)。不要将“默认操作”与“描述”混淆,它们不是一回事。

SIGINT用于表示进程的交互式“键盘中断”。有些程序可能会以特殊方式处理这种情况,以便终端用户使用。

SIGHUP用于表示终端已消失且不再查看该过程。就这些。一些进程选择关闭响应,通常是因为没有终端它们的操作没有意义,有些进程选择执行其他操作,例如重新检查配置文件。

SIGKILL用于从内核强制删除进程。它的特殊之处在于它实际上并不是进程的信号,而是由内核直接解释。

不要发送SIGKILL。 SIGKILL肯定不会被脚本发送。如果应用程序处理SIGTERM,它可能需要一秒钟来清理,它可能需要一分钟,可能需要一个小时。取决于应用程序在准备结束之前必须完成的工作。 “假定”应用程序清理序列的任何逻辑已经花了足够长的时间,并且需要在X秒之后是快捷方式或SIGKILLed 只是完全错误

应用程序需要 SIGKILL终止的唯一原因 - 是在清理序列期间出现问题。在这种情况下,您可以手动打开终端和SIGKILL。除此之外,为什么你要SIGKILL的另一个原因是因为你想要以防止它自我清理。

即使世界上一半的人在5秒后盲目地发送SIGKILL,但仍然是非常错误的事情。

答案 1 :(得分:10)

简短回答:30秒后发送SIGTERM SIGKILL。也就是说,发送SIGTERM,等待一段时间(可能因程序而异,您可能会更好地了解您的系统,但5到30秒就足够了。关闭机器时,您可能会看到它自动等待到1 30s。为什么匆忙,毕竟?),然后发送SIGKILL

合理回答SIGTERMSIGINTSIGKILL 这绰绰有余。该流程非常可能会在SIGKILL之前终止。

长答案SIGTERMSIGINTSIGQUITSIGABRTSIGKILL

这是不必要的,但至少你没有误导有关你的信息的过程。所有这些信号执行意味着您希望进程停止正在执行的操作并退出。

无论您从这个解释中选择什么答案,请记住这一点!

如果您发送的信号意味着其他信号,则该过程可能会以非常不同的方式处理(一方面)。另一方面,如果进程没有处理信号,那么毕竟你发送的内容并不重要,无论如何都会退出进程(当然,当默认操作终止时)。

所以,你必须把自己想象成一个程序员。你会编写一个函数处理程序,比方说,SIGHUP退出一个与某个东西连接的程序,或者你会循环它以尝试再次连接?这是主要问题!这就是为什么发送意味着你想要的信号很重要的原因。

几乎愚蠢的长答案

下表包含相关信号,以及程序无法处理时的默认操作。

我按照我建议的顺序订购了它们(顺便说一下,我建议你使用合理的答案,而不是这里的这个),如果你真的需要全部尝试(它会是有趣的是,表格是根据它们可能造成的破坏而排序的,但这不是完全真实的)。

带星号(*)的信号建议 NOT 。关于这些的重要一点是你可能永远不知道它的编程是做什么的。特别是SIGUSR!它可以启动apocalipse(这是程序员做任何他/她想做的免费信号!)。但是,如果不处理 OR ,在不太可能的情况下处理终止,程序将终止。

在表格中,具有终止和生成核心转储的默认选项的信号最后留在SIGKILL之前。

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGTERM      15       Term    Termination signal
SIGINT        2       Term    Famous CONTROL+C interrupt from keyboard
SIGHUP        1       Term    Disconnected terminal or parent died
SIGPIPE      13       Term    Broken pipe
SIGALRM(*)   14       Term    Timer signal from alarm
SIGUSR2(*)   12       Term    User-defined signal 2
SIGUSR1(*)   10       Term    User-defined signal 1
SIGQUIT       3       Core    CONTRL+\ or quit from keyboard
SIGABRT       6       Core    Abort signal from abort(3)
SIGSEGV      11       Core    Invalid memory reference
SIGILL        4       Core    Illegal Instruction
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal

然后我建议这个几乎愚蠢的长答案SIGTERMSIGINTSIGHUPSIGPIPESIGQUITSIGABRTSIGKILL

最后,

绝对愚蠢的漫长答案

不要在家里试试。

SIGTERMSIGINTSIGHUPSIGPIPESIGALRMSIGUSR2SIGUSR1SIGQUITSIGABRTSIGSEGVSIGILLSIGFPE,如果没有效果,SIGKILL

SIGUSR2应该在SIGUSR1之前尝试,因为如果程序没有处理信号,我们会更好。如果它只处理其中一个,它更有可能处理SIGUSR1

BTW,KILL :将SIGKILL发送给流程并没有错,正如其他答案所述。那么,想想发送shutdown命令时会发生什么?它只会尝试SIGTERMSIGKILL。为什么你认为是这样的?如果非常shutdown命令只使用这两个信号,为什么还需要其他信号?

现在,回到长回答,这是一个很好的oneliner:

for SIG in 15 2 3 6 9 ; do echo $SIG ; echo kill -$SIG $PID || break ; sleep 30 ; done

它在信号之间休眠30秒。为什么还需要 oneliner ? ;)

此外,建议:仅使用合理答案中的信号15 2 9进行尝试。

安全:当您准备好时,删除第二个echo。我称之为在线人员,我称之为dry-run。总是用它来测试。

剧本杀人

实际上我对这个问题很感兴趣,于是我决定创建一个小脚本来做到这一点。请随意下载(克隆)它:

GitHub链接到Killgracefully repository

答案 2 :(得分:6)

通常你会发送SIGTERM,默认为kill。这是默认的原因。只有当程序在合理的时间内没有关闭时才能使用SIGKILL。但请注意,对于SIGKILL,程序无法清理数据并且数据可能已损坏。

至于SIGHUPHUP代表“挂断”,历史上意味着调制解调器已断开连接。它基本上等同于SIGTERM。守护进程有时使用SIGHUP重新启动或重新加载配置的原因是守护进程从任何控制终端分离,因为守护进程不需要那些,因此永远不会收到SIGHUP,因此该信号被视为“释放“一般用途。并非所有守护进程都使用它来重新加载! SIGHUP的默认操作是终止,许多守护进程表现如此!所以你不能盲目地将SIGHUP发送给守护进程并期望它们存活下来。

编辑: SIGINT可能不适合终止进程,因为它通常与^C或终端设置中断程序无关。许多程序都是为了自己的目的而捕获它,因此它不常用。 SIGQUIT通常默认创建核心转储,除非你想要核心文件,否则它也不是一个好的候选者。

摘要:如果您发送SIGTERM并且该计划未在您的时间范围内死亡,请发送SIGKILL

答案 3 :(得分:5)

SIGTERM 实际上意味着向应用程序发送消息:“你会如此善良并自杀”。它可以被应用程序捕获和处理,以运行清理和关闭代码。

SIGKILL 无法被应用程序捕获。应用程序被操作系统杀死而没有任何清理机会。

通常首先发送SIGTERM,稍稍休息一下,然后发送SIGKILL

答案 4 :(得分:3)

  • SIGTERM等同于“在窗口中点击'X'”。
  • SIGTERM是Linux在关闭时首先使用的。

答案 5 :(得分:1)

所有讨论都在这里进行,没有提供任何代码。这是我的看法:

#!/bin/bash

$pid = 1234

echo "Killing process $pid..."
kill $pid

waitAttempts=30 
for i in $(seq 1 $waitAttempts)
do
    echo "Checking if process is alive (attempt #$i / $waitAttempts)..."
    sleep 1

    if ps -p $pid > /dev/null
    then
        echo "Process $pid is still running"
    else
        echo "Process $pid has shut down successfully"
        break
    fi
done

if ps -p $pid > /dev/null
then
    echo "Could not shut down process $pid gracefully - killing it forcibly..."
    kill -SIGKILL $pid
fi

答案 6 :(得分:0)

HUP对我来说听起来像垃圾。我发送它来获取守护进程重新读取其配置。

可以拦截SIGTERM;您的守护进程可能会在收到该信号时运行清理代码。你不能为SIGKILL做到这一点。因此,使用SIGKILL,您不会给守护程序的作者任何选项。

有关Wikipedia

的详情