107

在对另一个问题这个答案的评论中,评论者说:

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

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

鉴于这SIGKILL是最后的手段——你应该将哪些信号以及以什么顺序发送到任意进程,以便尽可能优雅地关闭它?

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

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

编辑:到目前为止,似乎没有人提到 INT 或 QUIT,而且很少提到 HUP。是否有任何理由将这些包含在有序的进程终止中?

4

7 回答 7

138

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

有些人认为终止进程的智能标准方法是向它发送一系列信号,例如 HUP、INT、TERM 和最后的 KILL。这是荒唐的。终止的正确信号是 SIGTERM,如果 SIGTERM 没有立即终止进程,正如您可能更喜欢的那样,那是因为应用程序已选择处理该信号。这意味着它有一个很好的理由不立即终止:它有清理工作要做。如果您使用其他信号中断清理工作,则无法确定内存中的哪些数据尚未保存到磁盘,哪些客户端应用程序处于挂起状态,或者您是否在“句子中间”中断它,这实际上是数据损坏。

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

SIGINT 用于发出进程的交互式“键盘中断”信号。某些程序可能会出于终端用户的目的以特殊方式处理这种情况。

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

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

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

应用程序需要SIGKILL 终止的唯一原因是,如果在其清理过程中出现问题。在这种情况下,您可以打开一个终端并手动 SIGKILL 它。除此之外,您要 SIGKILL 某些东西的唯一另一个原因是因为您阻止它自行清理。

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

于 2009-03-27T17:07:51.527 回答
24

简短回答:发送SIGTERM,30 秒后,SIGKILL。即发送SIGTERM,稍等(可能因程序而异,您可能更了解您的系统,但 5 到 30 秒就足够了。关闭机器时,您可能会看到它自动等待长达 1'30 秒。毕竟为什么这么着急?),然后发送SIGKILL.

合理答案SIGTERM,,,SIGINTSIGKILL 绰绰有余。该过程可能会在之前终止SIGKILL

答案:,,,,,, SIGTERM_ SIGINT_SIGQUITSIGABRTSIGKILL

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

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

如果您发送一个意味着其他东西的信号,该过程可能会以非常不同的方式处理它(一方面)。另一方面,如果进程不处理信号,那么无论你发送什么都无关紧要,进程无论如何都会退出(当然,当默认操作是终止时)。

因此,您必须将自己视为程序员。你会编写一个函数处理程序,比如说,SIGHUP退出与某物连接的程序,还是循环它以尝试再次连接?这是这里的主要问题!这就是为什么只发送意味着你想要的信号很重要的原因。

几乎愚蠢的长答案

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

我按照我建议使用的顺序订购了它们(顺便说一句,我建议您使用合理的答案,而不是这里的这个),如果您真的需要全部尝试(如果说桌子是按照以下顺序排列的,那会很有趣它们可能造成的破坏,但这并不完全正确)。

推荐使用带星号 (*) 的信号。关于这些的重要一点是,您可能永远不知道它被编程做什么。特别SIGUSR!它可能会开始启示录(对于程序员来说这是一个自由信号,可以做任何他/她想做的事情!)。但是,如果不处理在不太可能的情况下处理终止,程序将终止。

在表中,带有用于终止和生成核心转储的默认选项的信号留在最后,就在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

然后我会建议这个几乎愚蠢的长答案: SIGTERM,,,,,,,,,SIGINTSIGHUPSIGPIPESIGQUITSIGABRTSIGKILL

最后,

绝对是愚蠢的长长的答案

不要在家里尝试这个。

SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGALRM, SIGUSR2, SIGUSR1, , , , , , , , , , , , , , , , , , SIGQUIT, SIGABRT, SIGSEGV, , .SIGILLSIGFPESIGKILL

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

顺便说一句, KILLSIGKILL :正如其他答案所述,发送到进程并没有错。好吧,想想当你发送shutdown命令时会发生什么?SIGTERM它只会尝试SIGKILL。你认为为什么会这样?shutdown如果命令只使用这两个,为什么还需要任何其他信号?


现在,回到长答案,这是一个不错的单行:

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网民。总是用它来测试。


优雅地编写脚本

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

Killgracefully 存储库的 GitHub 链接

于 2016-06-08T02:47:28.507 回答
8

通常你会发送SIGTERM,默认的 kill。这是默认设置是有原因的。只有当程序在合理的时间内没有关闭时,您才应该求助于SIGKILL. 但请注意,SIGKILL该程序无法清理数据,数据可能已损坏。

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

编辑: SIGINT终止进程可能不合适,因为它通常与^C终端设置相关或中断程序。许多程序出于自己的目的捕获它,因此它很常见以至于它不起作用。SIGQUIT通常具有创建核心转储的默认设置,除非您希望将核心文件放在它周围,否则也不是一个好的选择。

摘要:如果您发送SIGTERM并且程序没有在您的时间范围内死亡,那么发送它SIGKILL

于 2009-03-27T16:24:54.453 回答
7

SIGTERM实际上是指给应用程序发送一条消息:“你会这么好心去自杀吗”。它可以被应用程序捕获和处理以运行清理和关闭代码。

SIGKILL不能被应用程序捕获。应用程序被操作系统杀死,没有任何清理的机会。

通常先发送SIGTERM,休眠一段时间,然后发送SIGKILL

于 2009-03-27T16:53:43.183 回答
4
  • SIGTERM 相当于在窗口中“单击'X'”。
  • SIGTERM 是 Linux 在关闭时首先使用的。
于 2009-03-27T16:20:28.567 回答
4

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

#!/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
于 2017-01-26T19:36:42.810 回答
0

HUP对我来说听起来很垃圾。我会把它发送给一个守护进程来重新读取它的配置。

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

更多关于维基百科的信息

于 2009-03-27T16:26:16.227 回答