我应该以什么样的顺序发送信号以正常关机?

评论者对另一个问题的 回答评论说:

除非绝对必要,否则不要使用kill -9! SIGKILL不能被困住,所以被杀的程序不能运行任何关机例程来擦除临时文件。 首先尝试HUP(1),然后INT(2),然后QUIT(3)

我原则上同意SIGKILL ,但其余的消息给我。 鉴于kill发送的默认信号是SIGTERM ,我认为这是任意进程正常closures的最常见的信号。 另外,我已经看到SIGHUP用于非终止的原因,比如告诉守护进程“重新读取你的configuration文件”。 而在我看来, SIGINT (与Ctrl-C相同的中断,对吗?)没有得到广泛的支持,或者是非常不正常的结束。

鉴于SIGKILL是最后的select – 哪些信号,以什么样的顺序发送到一个任意的进程,以尽可能优雅地closures它?

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

注:我特别感兴趣的最佳做法,包括考虑bash / Cygwin。

编辑:到目前为止,似乎没有人提到INT或QUIT,并且HUP的提及有限。 有什么理由把这些包括在一个有序的过程中?

SIGTERM告诉应用程序终止。 其他信号告诉应用程序其他与关机无关的事情,但有时可能会有相同的结果。 不要使用这些。 如果你想要一个应用程序closures,告诉它。 不要给它误导性的信号。

有些人认为终结一个过程的智能标准方式是发送一个信号,比如HUP,INT,TERM,最后是KILL。 这是荒唐的。 正确的终止信号是SIGTERM,如果SIGTERM没有立即终止这个过程,你可能会喜欢,这是因为应用程序select了处理信号。 这意味着它有一个很好的理由不立即终止:它有清理工作要做。 如果你用其他信号中断了这个清理工作,就不知道内存中还没有保存到磁盘上的数据,还有什么客户端应用程序被挂起,或者是否中断了“中间语句”,这实际上是数据损坏。

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

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

SIGHUP用于表示terminal已经消失,不再看这个过程。 就这些。 有些进程selectclosures响应,一般是因为没有terminal,他们的操作没有意义,有些select做其他事情,比如重新检查configuration文件。

SIGKILL用于强制从内核中删除进程。 在这个意义上说,它并不是实际上是进程的信号,而是直接被内核解释。

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

为什么一个应用程序需要一个SIGKILL来终止的唯一原因是,如果在清理过程中出现错误。 在这种情况下,您可以手动打开terminal并SIGKILL。 除此之外,你为什么要SIGKILL的唯一一个其他原因是因为你想阻止它清理自己。

这并不是因为世界上有一半的人在5秒后使用SIGKILL,这并不是非常错误的。

SIGTERM实际上意味着给应用程序发送一条消息:“ 你会如此善良并自杀 ”。 它可以被应用程序困住并处理,以运行清理和closures代码。

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

首先发送SIGTERM ,hibernate一段时间,然后发送SIGKILL

通常你会发送SIGTERM ,这是kill的默认值。 这是默认的原因。 只有一个程序没有在合理的时间内closures,你应该求助于SIGKILL 。 但是请注意,在SIGKILL ,程序不可能清理干净,数据可能被破坏。

至于SIGHUPHUP代表“挂断”,历史意味着调制解调器断开连接。 它基本上等同于SIGTERM 。 守护进程有时使用SIGHUP来重新启动或重新加载configuration的原因是守护进程与任何控制terminal分离,因为守护进程不需要这些terminal,因此永远不会收到SIGHUP ,所以这个信号被认为是“释放”了一般用途。 并不是所有的守护进程都使用它来重新加载! SIGHUP的默认动作是终止,许多守护进程就是这样做的! 所以你不能盲目地将SIGHUP发送给守护进程,并希望它们能够生存。

编辑: SIGINT可能不适合终止进程,因为它通常与^C或任何terminal设置中断一个程序。 很多程序都是为了自己的目的而捕获的,所以它不常用。 SIGQUIT通常具有创build核心转储的默认设置,除非您希望在核心文件周围放置核心文件,这也不是一个好的select。

总结:如果你发送SIGTERM并且程序在你的时间范围内没有死掉,那么发送它SIGKILL

简答 :发送SIGTERM ,30秒后, SIGKILL 。 也就是说,发送SIGTERM ,稍等一下(不同的程序可能会有所不同,你可能会更好的了解你的系统,但是5到30秒就足够了,关机时你可能会自动等待1:30为什么匆忙,毕竟?),然后发送SIGKILL

合理的答案SIGTERMSIGINTSIGKILL这已经足够了。 这个过程可能会在SIGKILL之前终止。

长答案SIGTERMSIGINTSIGQUITSIGABRTSIGKILL

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

不pipe你从这个解释中select什么答案,记住这一点!

如果你发送的信号意味着其他的东西,这个过程可能会以不同的方式处理(一方面)。 另一方面,如果进程没有处理这个信号,那么不pipe你发送了什么,进程都会退出(当然当默认动作是终止的时候)。

所以,你必须像程序员一样认为自己。 你会编写一个函数处理程序吗?比方说, SIGHUP可以退出一个连接某个程序的程序,或者你会循环它来尝试再次连接? 这是这里的主要问题! 这就是为什么发送信号意味着什么是重要的。

几乎愚蠢的长答案

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

我按照我build议使用的顺序命令他们(顺便说一句,我build议你使用合理的答案 ,而不是在这里),如果你真的需要尝试所有的(这将是有趣的说,表是按照他们可能造成的破坏,但这并非完全正确)。

带星号(*)的信号推荐使用。 关于这些重要的是你可能永远不知道它被编程做什么。 特别是SIGUSR ! 它可能会启动apocalipse(对于程序员来说,这是一个免费的信号,不pipe他想要什么!)。 但是,如果不处理, 在不太可能的情况下处理终止,程序将终止。

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

那么我会build议这个几乎愚蠢的长答案SIGTERMSIGINTSIGHUPSIGPIPESIGQUITSIGABRTSIGKILL

最后,

绝对愚蠢的多头答案

不要在家里尝试。

SIGTERMSIGINTSIGHUPSIGPIPESIGALRMSIGUSR2SIGUSR1SIGQUITSIGABRTSIGSEGVSIGILLSIGFPE ,如果什么都不起作用, SIGKILL

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

顺便说一下,KILL :把SIGKILL发送到一个进程是没有错的,正如其他答案所述。 那么,想想你发送shutdown命令会发生什么? 它只会尝试SIGTERMSIGKILL 。 你为什么这么认为呢? 为什么你需要任何其他信号,如果非常shutdown命令只使用这两个?


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

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

它在信号之间hibernate30秒。 为什么你会需要一个oneliner ? ;)

另外,推荐:只用合理的答案 15 2 9信号。

安全性 :当你准备好去的时候去掉第二个echo 。 我把它称为我的网上 dry-run 。 总是用它来testing。


脚本可以杀死

其实我对这个问题非常感兴趣,所以我决定创build一个小脚本来做到这一点。 请在这里下载(克隆):

GitHub链接到Killgracefully存储库

  • SIGTERM相当于在窗口中单击“X”。
  • SIGTERM是Linux在closures时首先使用的。

HUP听起来像垃圾对我来说。 我会发送它来获得一个守护进程重新读取其configuration。

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

更多关于维基百科

所有的讨论都在这里进行,没有提供代码。 这是我的意见:

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