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

发布于 2024-07-16 11:13:23 字数 1008 浏览 5 评论 0 原文

评论中关于另一个这个答案 526782">问题,评论者说:

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

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

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

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

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

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

In a comment on this answer of another question, the commenter says:

don’t use kill -9 unless absolutely
necessary! SIGKILL can’t be trapped so
the killed program can’t run any
shutdown routines to e.g. erase
temporary files. First try HUP (1),
then INT (2), then QUIT (3)

I agree in principle about SIGKILL, but the rest is news to me. Given that the default signal sent by kill is SIGTERM, I would expect it is the most-commonly expected signal for graceful shutdown of an arbitrary process. Also, I have seen SIGHUP used for non-terminating reasons, such as telling a daemon "re-read your config file." And it seems to me that SIGINT (the same interrupt you'd typically get with Ctrl-C, right?) isn't as widely supported as it ought to be, or terminates rather ungracefully.

Given that SIGKILL is a last resort — Which signals, and in what order, should you send to an arbitrary process, in order to shut it down as gracefully as possible?

Please substantiate your answers with supporting facts (beyond personal preference or opinion) or references, if you can.

Note: I am particularly interested in best practices that include consideration of bash/Cygwin.

Edit: So far, nobody seems to mention INT or QUIT, and there's limited mention of HUP. Is there any reason to include these in an orderly process-killing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

诺曦 2024-07-23 11:13:24

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

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

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

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

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

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

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

应用程序需要一个SIGKILL来终止的唯一原因是在其清理序列期间是否出现了错误。 在这种情况下,您可以打开终端并手动 SIGKILL 它。 除此之外,您对某些东西SIGKILL的唯一另一个原因是您想要阻止它自行清理。

尽管世界上一半的人在 5 秒后盲目地发送 SIGKILL,但这仍然是非常错误的做法。

SIGTERM tells an application to terminate. The other signals tell the application other things which are unrelated to shutdown but may sometimes have the same result. Don't use those. If you want an application to shut down, tell it to. Don't give it misleading signals.

Some people believe the smart standard way of terminating a process is by sending it a slew of signals, such as HUP, INT, TERM and finally KILL. This is ridiculous. The right signal for termination is SIGTERM and if SIGTERM doesn't terminate the process instantly, as you might prefer, it's because the application has chosen to handle the signal. Which means it has a very good reason to not terminate immediately: It's got cleanup work to do. If you interrupt that cleanup work with other signals, there's no telling what data from memory it hasn't yet saved to disk, what client applications are left hanging or whether you're interrupting it "mid-sentence" which is effectively data corruption.

For more information on what the real meaning of the signals is, see sigaction(2). Don't confuse "Default Action" with "Description", they are not the same thing.

SIGINT is used to signal an interactive "keyboard interrupt" of the process. Some programs may handle the situation in a special way for the purpose of terminal users.

SIGHUP is used to signal that the terminal has disappeared and is no longer looking at the process. That is all. Some processes choose to shut down in response, generally because their operation makes no sense without a terminal, some choose to do other things such as recheck configuration files.

SIGKILL is used to forcefully remove the process from the kernel. It is special in the sense that it's not actually a signal to the process but rather gets interpreted by the kernel directly.

Don't send SIGKILL. - SIGKILL should certainly never be sent by scripts. If the application handles the SIGTERM, it can take it a second to cleanup, it can take a minute, it can take an hour. Depending on what the application has to get done before it's ready to end. Any logic that "assumes" an application's cleanup sequence has taken long enough and needs to be shortcut or SIGKILLed after X seconds is just plain wrong.

The only reason why an application would need a SIGKILL to terminate, is if something bugged out during its cleanup sequence. In which case you can open a terminal and SIGKILL it manually. Aside from that, the only one other reason why you'd SIGKILL something is because you WANT to prevent it from cleaning itself up.

Even though half the world blindly sends SIGKILL after 5 seconds it's still horribly wrong thing to do.

山川志 2024-07-23 11:13:24

简短回答:发送 SIGTERM,30 秒后发送 SIGKILL。 也就是发送SIGTERM,稍等一下(不同程序可能会有所不同,你可能更了解你的系统,但是5到30秒就足够了。当关闭机器时,你可能会看到它自动等待 1'30 秒。毕竟为什么要这么着急呢?),然后发送 SIGKILL

合理答案SIGTERMSIGINTSIGKILL
这已经足够了。 该进程非常可能会在SIGKILL之前终止。

长答案SIGTERMSIGINTSIGQUITSIGABRTSIGKILL

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

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

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

所以,作为一名程序员,你必须像你自己一样思考。 您是否会编写一个函数处理程序,例如,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

那么我会建议这个几乎愚蠢的长答案
SIGTERMSIGINTSIGHUPSIGPIPESIGQUITSIGABRT< /code>, SIGKILL

最后,

绝对愚蠢的长长答案

不要在家尝试这个。

SIGTERMSIGINTSIGHUPSIGPIPESIGALRMSIGUSR2< /code>、SIGUSR1SIGQUITSIGABRTSIGSEGVSIGILL、< code>SIGFPE 如果没有任何效果,则 SIGKILL

SIGUSR2 应该在 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

它在信号之间休眠 30 秒。 否则为什么您需要一个oneliner? ;)

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

安全:当您准备出发时,移除第二个回声。 我将其称为我的在线试运行。 始终用它来测试。


编写killgracely脚本

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

Killgraceously 存储库 的 GitHub 链接

Short Answer: Send SIGTERM, 30 seconds later, SIGKILL. That is, send SIGTERM, wait a bit (it may vary from program to program, you may know your system better, but 5 to 30 seconds is enough. When shutting down a machine, you may see it automatically waiting up to 1'30s. Why the hurry, after all?), then send SIGKILL.

Reasonable Answer: SIGTERM, SIGINT, SIGKILL
This is more than enough. The process will very probably terminate before SIGKILL.

Long Answer: SIGTERM, SIGINT, SIGQUIT, SIGABRT, SIGKILL

This is unnecessary, but at least you are not misleading the process regarding your message. All these signals do mean you want the process to stop what it is doing and exit.

No matter what answer you choose from this explanation, keep that in mind!

If you send a signal that means something else, the process may handle it in very different ways (on one hand). On the other hand, if the process doesn't handle the signal, it doesn't matter what you send after all, the process will quit anyway (when the default action is to terminate, of course).

So, you must think as yourself as a programmer. Would you code a function handler for, lets say, SIGHUP to quit a program that connects with something, or would you loop it to try to connect again? That is the main question here! That is why it is important to just send signals that mean what you intend.

Almost Stupid Long Answer:

The table bellow contains the relevant signals, and the default actions in case the program does not handle them.

I ordered them in the order I suggest to use (BTW, I suggest you to use the reasonable answer, not this one here), if you really need to try them all (it would be fun to say the table is ordered in terms of the destruction they may cause, but that is not completely true).

The signals with an asterisk (*) are NOT recommended. The important thing about these is that you may never know what it is programmed to do. Specially SIGUSR! It may start the apocalipse (it is a free signal for a programmer do whatever he/she wants!). But, if not handled OR in the unlikely case it is handled to terminate, the program will terminate.

In the table, the signals with default options to terminate and generate a core dump are left in the end, just before 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

Then I would suggest for this almost stupid long answer:
SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGQUIT, SIGABRT, SIGKILL

And finally, the

Definitely Stupid Long Long Answer:

Don't try this at home.

SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGALRM, SIGUSR2, SIGUSR1, SIGQUIT, SIGABRT, SIGSEGV, SIGILL, SIGFPE and if nothing worked, SIGKILL.

SIGUSR2 should be tried before SIGUSR1 because we are better off if the program doesn't handle the signal. And it is much more likely for it to handle SIGUSR1 if it handles just one of them.

BTW, the KILL: it is not wrong to send SIGKILL to a process, as other answer stated. Well, think what happens when you send a shutdown command? It will try SIGTERM and SIGKILL only. Why do you think that is the case? And why do you need any other signals, if the very shutdown command uses only these two?


Now, back to the long answer, this is a nice oneliner:

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

It sleeps for 30 seconds between signals. Why else would you need a oneliner? ;)

Also, recommended: try it with only signals 15 2 9 from the reasonable answer.

safety: remove the second echo when you are ready to go. I call it my dry-run for onliners. Always use it to test.


Script killgracefully

Actually I was so intrigued by this question that I decided to create a small script to do just that. Please, feel free to download (clone) it here:

GitHub link to Killgracefully repository

撩心不撩汉 2024-07-23 11:13:24

通常,您会发送 SIGTERM,默认为终止。 这是默认设置是有原因的。 只有当程序没有在合理的时间内关闭时,您才应该使用 SIGKILL。 但请注意,使用 SIGKILL 程序无法清理内容并且数据可能会损坏。

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

编辑: SIGINT 可能不适合终止进程,因为它通常与 ^C 或任何用于中断程序的终端设置相关联。 许多程序都会出于自己的目的捕获此信息,因此它很常见,因此无法正常工作。 SIGQUIT 通常默认创建核心转储,除非您想要核心文件,否则它也不是一个好的候选者。

摘要:如果您发送 SIGTERM 并且程序没有在您的时间范围内终止,则发送 SIGKILL

Typically you'd send SIGTERM, the default of kill. It's the default for a reason. Only if a program does not shutdown in a reasonable amount of time should you resort to SIGKILL. But note that with SIGKILL the program has no possibility to clean things up und data could be corrupted.

As for SIGHUP, HUP stands for "hang up" and historically meant that the modem disconnected. It's essentially equivalent to SIGTERM. The reason that daemons sometimes use SIGHUP to restart or reload config is that daemons detach from any controlling terminals as a daemon doesn't need those and therefore would never receive SIGHUP, so that signal was considered as "freed up" for general use. Not all daemons use this for reload! The default action for SIGHUP is to terminate and many daemons behave that way! So you can't go blindly sending SIGHUPs to daemons and expecting them to survive.

Edit: SIGINT is probably inappropriate to terminate a process, as it's normally tied to ^C or whatever the terminal setting is to interrupt a program. Many programs capture this for their own purposes, so it's common enough for it not to work. SIGQUIT typically has the default of creating a core dump, and unless you want core files laying around it's not a good candidate, either.

Summary: if you send SIGTERM and the program doesn't die within your timeframe then send it SIGKILL.

心房敞 2024-07-23 11:13:24

SIGTERM 实际上意味着向应用程序发送一条消息:“你愿意自杀吗”。 它可以被应用程序捕获和处理以运行清理和关闭代码。

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

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

SIGTERM actually means sending an application a message: "would you be so kind and commit suicide". It can be trapped and handled by application to run cleanup and shutdown code.

SIGKILL cannot be trapped by application. Application gets killed by OS without any chance for cleanup.

It's typical to send SIGTERM first, sleep some time, then send SIGKILL.

空名 2024-07-23 11:13:24
  • SIGTERM 相当于“单击窗口中的‘X’”。
  • SIGTERM 是 Linux 在关闭时首先使用的信号。
  • SIGTERM is equivalent to "clicking the 'X' " in a window.
  • SIGTERM is what Linux uses first, when it is shutting down.
夕嗳→ 2024-07-23 11:13:24

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

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

With all the discussion going on here, no code has been offered. Here's my take:

#!/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
如此安好 2024-07-23 11:13:24

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

SIGTERM可以被拦截; 您的守护进程可能会在收到该信号时运行清理代码。 您不能对 SIGKILL 执行此操作。 因此,使用 SIGKILL 您不会为守护进程的作者提供任何选项。

有关更多信息,请访问维基百科

HUP sounds like rubbish to me. I'd send it to get a daemon to re-read its configuration.

SIGTERM can be intercepted; your daemons just might have clean-up code to run when it receives that signal. You cannot do that for SIGKILL. Thus with SIGKILL you are not giving the daemon's author any options.

More on that on Wikipedia

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文