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


87

评论这个答案的另一个问题,该评论说:

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

我原则上同意SIGKILL,但是其余对我来说就是新闻。鉴于发送的默认信号killSIGTERM,我希望它是正常关闭任意进程的最普遍期望的信号。另外,我还看到了SIGHUP出于非终止原因使用的原因,例如告诉守护程序“重新读取配置文件”。在我看来,SIGINT(通常与Ctrl-C相同的中断,对吗?)并没有得到应有的广泛支持,或者以不合时宜的方式终止。

鉴于这SIGKILL是万不得已的方法,您应该以哪种信号以及以什么顺序发送到任意进程,以便尽可能地正常关闭它?

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

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

编辑:到目前为止,似乎没有人提到INT或QUIT,并且很少提及HUP。是否有任何理由将它们包括在有序的过程中?


4
如果您必须诉诸SIGKILL来真正终止某个进程,我会认为它是程序中的错误。
sigjuice 2009年

Answers:


114

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

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

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

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

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

SIGKILL用于从内核中强制删除进程。从某种意义上说,它实际上不是进程的信号,而是由内核直接解释的,这是特别的。

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

应用程序需要SIGKILL终止的唯一原因是,如果在其清理序列中出现错误。在这种情况下,您可以打开一个终端并手动对其进行SIGKILL。除此之外,唯一的其他原因,为什么你会SIGKILL东西是因为你WANT,以防止其自我整顿。

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


13
您说得对,SIGKILL经常被滥用。但是,即使在脚本中也有使用它的时间和地点。许多应用程序会捕获SIGTERM,并在不到一秒钟或短短几秒钟内正常退出,其中一个仍在运行30秒后才运行,这是因为它被楔住了。
dwc

4
@dwc:尝试让它运行一次一个小时。如果它没有死,那就“楔住”并修复它,或者是懒惰的,并且在以后一段时间以后对其进行SIGKILL。 请注意,您可能正在破坏东西,请记住,这不是您应该“默认”执行的操作。
lhunath

2
@lhunath:希望您不要介意,我重新排列了您的段落,以使答案更直接,更清楚地从问题中得出。抗SIGKILL咆哮是好东西,但第二要点。再次感谢您提供出色的教育提示。
系统

8
不要发送SIGKILL。曾经 完全是错误的。真?即使您的系统已经由于无限循环而燃烧。祝好运。-1
konsolebox 2014年

//,为此,这是荒谬的。
弥敦道(Nathan Basanese)

17

简短答案SIGTERM30秒后发送SIGKILL。也就是说SIGTERM,稍等一下(发送,等待(每个程序可能有所不同,您可能对系统了解得更多,但是5到30秒就足够了。)关闭计算机时,您可能会看到它自动等待1'30秒。毕竟为什么要着急?),然后发送SIGKILL

合理的答案SIGTERMSIGINTSIGKILL 这是绰绰有余。该过程可能在之前终止SIGKILL

长的答案SIGTERMSIGINTSIGQUITSIGABRTSIGKILL

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

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

如果您发送的信号表示其他内容,则该过程可能会以非常不同的方式(一方面)处理该信号。另一方面,如果该进程不处理信号,则无论您发送什么内容都无所谓,该进程仍然会退出(当然,默认操作是终止时)。

因此,您必须像程序员一样思考。您是否愿意编写一个函数处理程序,SIGHUP以便退出一个与某物连接的程序,或者您将其循环以再次尝试连接?这是这里的主要问题!这就是为什么仅发送表示您意图的信号很重要的原因。

几乎愚蠢的长答案

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

如果您确实需要尝试全部使用它们,我可以按照我建议使用的顺序对其进行排序(顺便说一句,我建议您使用合理的答案,而不是此处的答案)(有趣的是,表的排列顺序是它们可能造成的破坏,但这并不是完全正确的)。

建议带星号(*)的信号。关于这些的重要事情是,您可能永远都不知道它的编程功能。特别是SIGUSR!它可能会启动apocalipese(这是程序员做他/她想要做的事的免费信号!)。但是,如果不处理在极少数情况下处理终止,程序将终止。

在该表中,最后带有缺省选项的信号可以终止并生成核心转储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如果只处理其中之一,则更有可能处理。

顺便说一句,杀人:发送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秒。您为什么还需要一个内衬?;)

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

安全echo准备就绪时,请取下第二个。我称其dry-run网上购物者。始终使用它进行测试。


优雅地杀死脚本

实际上,我对这个问题很感兴趣,因此我决定创建一个小的脚本来完成此操作。请随时在这里下载(克隆)它:

GitHub链接到Killgracefully仓库


8

通常,您会发送SIGTERM,默认为kill。由于某种原因,这是默认设置。仅当程序没有在合理的时间内关闭时,才应诉诸于此SIGKILL。但是请注意,使用SIGKILL该程序无法清除所有内容,并且数据可能已损坏。

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

编辑: SIGINT可能不适合终止进程,因为通常它与绑定^C或终止终端程序的程序无关。许多程序都是出于自己的目的捕获它的,因此它很常见,无法正常工作。SIGQUIT通常默认情况下会创建一个核心转储,并且除非您希望放置核心文件也不是一个好的选择。

简介:如果您发送SIGTERM并且程序没有在您的时间范围内消失,则发送它SIGKILL


4
请注意,只有在立即关闭比阻止数据丢失/数据损坏具有更高优先级的情况下,才应使用SIGKILL进行后续操作。
thomasrutter

@dwc我不明白您回答中的以下几点。您能帮忙吗?“守护程序有时使用SIGHUP重新启动或重新加载配置的原因是,守护程序与任何控制终端分离,因此永远不会收到SIGTERM,因此该信号被视为“释放”用于常规用途。”
杰克

3
@Jack让我尝试一下:SIGHUP是“挂断”信号,它告诉进程终端已断开连接。由于守护程序在后台运行,因此它们不需要终端。这意味着“挂断”信号与守护程序无关。他们永远不会从终端断开中收到它,因为他们首先没有连接终端。而且由于无论如何都定义了信号,尽管它们不需要达到原始目的,但许多守护程序却将其用于其他目的,例如重新读取其配置文件。
系统

谢谢系统暂停。这很有帮助。
2013年

6

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

SIGKILL无法被应用程序捕获。应用程序被操作系统杀死,没有机会进行清理。

通常先发送SIGTERM,睡觉一段时间,然后发送SIGKILL


我想轮询会比睡觉前(SIGKILL之前)更有效率
Ohad Schneider

@OhadSchneider可以,但是比简单的bash命令还需要更多。
vartec

是的,我想您可能需要使用以下方法在过程仍然存在时循环:stackoverflow.com/a/15774758/67824
Ohad Schneider

5
  • SIGTERM等效于在窗口中“单击'X'”。
  • SIGTERM是Linux在关闭时首先使用的工具。

这就是我想知道的。+1。谢谢。
吕克

6
“ SIGTERM等效于”在窗口中单击“ X””,不是,因为任何一个应用程序都可以轻松打开任意数量的(例如,文档和工具)窗口,更不用说对话框了,它可能无法打开。甚至像对退出命令一样对最后一个窗口关闭命令做出响应(我想不出任何明显的示例,但是虽然不是很明显,但没有理由不能那样做)。SIGTERM等效于(或应该等效于)优雅地要求应用程序终止,但是可以在该特定应用程序中执行
用户

3

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

#!/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

0

对我来说,HUP听起来像垃圾。我将其发送给守护程序以重新读取其配置。

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

有关Wikipedia的更多信息

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.