SIGINT与其他终止信号(如SIGTERM、SIGQUIT和SIGKILL)有何关联?

158
在POSIX系统上,终止信号通常按照以下顺序(根据许多MAN页面和POSIX规范):
1. SIGTERM - 礼貌地要求进程终止。它应该优雅地终止,清理所有资源(文件、套接字、子进程等),删除临时文件等。
2. SIGQUIT - 更有力的请求。它将不优雅地终止,仍然清理绝对需要清理的资源,但可能不会删除临时文件,可能会将调试信息写入某个地方;在某些系统上,还会写入核心转储(无论应用程序是否捕获到该信号)。
3. SIGKILL - 最有力的请求。进程甚至不被要求执行任何操作,但系统将清理该进程,无论它是否愿意。很可能会写入核心转储。

在这个情况下,SIGINT是如何适应的呢?当用户按下CRTL+C时,CLI进程通常会被SIGINT终止,然而,使用KILL实用程序也可以终止后台进程。我在规范或头文件中看不到SIGINT是否比SIGTERM更有力,或者SIGINTSIGTERM之间是否有任何区别。

更新:

到目前为止,我找到的关于终止信号的最佳描述是在GNU LibC文档中。它很好地解释了SIGTERM和SIGQUIT之间的有意区别。

关于SIGTERM,它说:

这是一种礼貌地要求程序终止的正常方式。

关于SIGQUIT,它说:

[...] 当进程终止时,就像程序错误信号一样,会产生核心转储。你可以将其视为用户“检测到”的程序错误条件。[...] 在处理SIGQUIT时,某些清理工作最好不要省略。例如,如果程序创建临时文件,应该通过删除临时文件来处理其他终止请求。但最好不要在SIGQUIT中删除它们,这样用户可以与核心转储一起检查它们。
而且,SIGHUP也有很好的解释。SIGHUP并不是真正的终止信号,它只是意味着与用户的“连接”已丢失,因此应用程序不能指望用户继续阅读任何输出(例如stdout/stderr输出),也不再需要从用户那里接收输入。对于大多数应用程序来说,这意味着它们最好退出。理论上,一个应用程序也可以决定在收到SIGHUP时进入守护进程模式,现在作为后台进程运行,并将输出写入配置的日志文件。对于已在后台运行的大多数守护进程,SIGHUP通常意味着它们应该重新检查其配置文件,因此在编辑配置文件后将其发送给后台进程。
然而,除了CRTL+C发送的信息外,此页面上没有关于SIGINT的有用解释。是否有任何原因会以不同的方式处理SIGINT而不是SIGTERM?如果是这样,这个原因是什么,处理方式又有何不同?

3
好问题。我怀疑一些古老的Unix代码可能与答案有关。 - Alex B
1
我知道这个问题很老了,但是如果有人在这里寻找(Linux)操作系统的信号的详尽列表,可以通过在命令提示符上键入sudo fuser -l来找到它们。对我来说,这会带出:HUP INT QUIT ILL TRAP ABRT IOT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH IO PWR SYS UNUSED - Nick Bull
4
另外尝试使用 kill -l 命令获取信号列表。 - AAAfarmclub
6个回答

133

SIGTERMSIGKILL用于一般目的的"终止此进程"请求。 SIGTERM(默认情况下)和SIGKILL(始终如此)将导致进程终止。 SIGTERM可以被进程捕获(例如,以便它可以进行自己的清理),甚至可以完全忽略;但是SIGKILL无法被捕获或忽略。

SIGINTSIGQUIT专门用于终端的请求:特定的输入字符可以被分配为生成这些信号(取决于终端控制设置)。 SIGINT的默认操作与SIGTERM的默认操作以及SIGKILL的不可更改操作相同,即进程终止;SIGQUIT的默认操作也是进程终止,但可能会发生其他实现定义的操作,例如生成核心转储。如果需要,进程可以捕获或忽略任何一个信号。

"SIGHUP",就像你所说的,旨在表示终端连接已丢失,而不是作为终止信号。但是,再次强调,如果进程没有捕获或忽略它,对于"SIGHUP"的默认操作与"SIGTERM"等信号相同,即终止进程。
POSIX定义中有一张表格,列出了各种信号及其默认操作和目的,而General Terminal Interface章节则提供了关于与终端相关的信号的更多详细信息。此外,signal.h中也有相关的定义。

18
这是关键点:在程序运行时,可以使用单个字符从终端生成SIGINT和SIGQUIT信号。而其他信号必须通过另一个程序(例如kill命令)生成。SIGINT比SIGQUIT更温和;后者会产生核心转储。SIGKILL无法被捕获。如果连接断开(窗口关闭等),将生成SIGHUP信号。因此,它们都有不同的含义。 - Jonathan Leffler
1
TTY Demystified提供了一些易于理解的信息,介绍了信号如何与内核的tty子系统交互。这为你的答案增加了一些背景。 - Daniel Näslund
3
看起来规格不是非常精确,但我的理解是SIgint要求程序停止当前的操作,而不一定是退出。对于一个只设计每次运行执行一项操作的程序,这意味着退出,但对于一个具有某种读取-评估-打印循环的交互式程序,它可以意味着放弃当前的评估并返回读取用户输入。我认为less在sigint时就是这样做的。 - bdsl
1
重启期间发送了什么信号? - Dan Dascalescu
2
@bdsl 谢谢,伙计。我在互联网上搜索了一半,最终找到了你的评论。这正是你所说的,我已经用 ftp 进行了检查 - 这是一个交互式程序,当输入 open hostname 时,程序可能会阻塞,只有按下 C-c 才能停止此 open 操作,而不是整个程序!此外,应清楚地指出,这仅是对程序的提示:其他程序可能不会像 ftp 那样表现,但我认为它们应该像 ftp 一样处理这些信号,因为这是一种良好的编程实践,可以使事情可预测。伙计们,投票支持 bdsl 的评论! - rychu

18

man 7 signal

这是Linux man-pages project的便捷非规范手册,您经常需要查看其中的Linux信号信息。

版本3.22提到了一些有趣的事情,例如:

信号SIGKILL和SIGSTOP无法被捕获、阻止或忽略。

并包含以下表格:

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGHUP        1       Term    Hangup detected on controlling terminal
                              or death of controlling process
SIGINT        2       Term    Interrupt from keyboard
SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal
SIGSEGV      11       Core    Invalid memory reference
SIGPIPE      13       Term    Broken pipe: write to pipe with no
                              readers
SIGALRM      14       Term    Timer signal from alarm(2)
SIGTERM      15       Term    Termination signal
SIGUSR1   30,10,16    Term    User-defined signal 1
SIGUSR2   31,12,17    Term    User-defined signal 2
SIGCHLD   20,17,18    Ign     Child stopped or terminated
SIGCONT   19,18,25    Cont    Continue if stopped
SIGSTOP   17,19,23    Stop    Stop process
SIGTSTP   18,20,24    Stop    Stop typed at tty
SIGTTIN   21,21,26    Stop    tty input for background process
SIGTTOU   22,22,27    Stop    tty output for background process

这段文字概括了信号中的Action,用于区分例如SIGQUIT和SIGINT等不同信号,因为SIGQUIT的操作是Core,而SIGINT的操作是Term

这些操作在同一文档中有详细记录:

The entries in the "Action" column of the tables below specify the default disposition for each signal, as follows:

Term   Default action is to terminate the process.

Ign    Default action is to ignore the signal.
Core   Default action is to terminate the process and dump core (see core(5)).
Stop   Default action is to stop the process.
Cont   Default action is to continue the process if it is currently stopped.

就内核而言,我无法看出SIGTERM和SIGINT之间的任何区别,因为两者都有Term操作,并且都可以被捕获。似乎这只是一种“常见用法约定区别”:

  • SIGINT是从终端执行CTRL-C时发生的情况
  • SIGTERM是由kill发送的默认信号

某些信号是ANSI C而其他信号不是

一个相当大的区别是:

  • SIGINT和SIGTERM是ANSI C,因此更具可移植性
  • SIGQUIT和SIGKILL则不是

它们在C99 draft N1256的“7.14信号处理”部分中进行了描述:

  • SIGINT交互式注意信号的接收
  • SIGTERM向程序发送终止请求

这使得SIGINT成为交互式Ctrl + C的理想候选。

POSIX 7

POSIX 7文件使用signal.h头文件记录了信号: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html

此页面还有一个相关的表格,提到了我们已经在man 7 signal中看到的一些内容:

Signal    Default Action   Description
SIGABRT   A                Process abort signal.
SIGALRM   T                Alarm clock.
SIGBUS    A                Access to an undefined portion of a memory object.
SIGCHLD   I                Child process terminated, stopped,
SIGCONT   C                Continue executing, if stopped.
SIGFPE    A                Erroneous arithmetic operation.
SIGHUP    T                Hangup.
SIGILL    A                Illegal instruction.
SIGINT    T                Terminal interrupt signal.
SIGKILL   T                Kill (cannot be caught or ignored).
SIGPIPE   T                Write on a pipe with no one to read it.
SIGQUIT   A                Terminal quit signal.
SIGSEGV   A                Invalid memory reference.
SIGSTOP   S                Stop executing (cannot be caught or ignored).
SIGTERM   T                Termination signal.
SIGTSTP   S                Terminal stop signal.
SIGTTIN   S                Background process attempting read.
SIGTTOU   S                Background process attempting write.
SIGUSR1   T                User-defined signal 1.
SIGUSR2   T                User-defined signal 2.
SIGTRAP   A                Trace/breakpoint trap.
SIGURG    I                High bandwidth data is available at a socket.
SIGXCPU   A                CPU time limit exceeded.
SIGXFSZ   A                File size limit exceeded.

忙碌箱初始化

BusyBox 1.29.2 默认的 reboot 命令会向进程发送 SIGTERM 信号,等待一秒钟,然后发送 SIGKILL 信号。这似乎是不同发行版之间的常见惯例。

当您关闭 BusyBox 系统时:

reboot

我会尽力帮助您进行翻译。以下是需要翻译的内容:

它向 init 进程发送一个信号。

然后,init 信号处理程序最终会调用:

static void run_shutdown_and_kill_processes(void)
{
    /* Run everything to be run at "shutdown".  This is done _prior_
     * to killing everything, in case people wish to use scripts to
     * shut things down gracefully... */
    run_actions(SHUTDOWN);

    message(L_CONSOLE | L_LOG, "The system is going down NOW!");

    /* Send signals to every process _except_ pid 1 */
    kill(-1, SIGTERM);
    message(L_CONSOLE, "Sent SIG%s to all processes", "TERM");
    sync();
    sleep(1);

    kill(-1, SIGKILL);
    message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
    sync();
    /*sleep(1); - callers take care about making a pause */
}

这将打印到终端:

The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes

这里是一个最简单的实例

内核发送的信号


10

正如DarkDust所指出的,许多信号具有相同的结果,但是通过区分每个信号生成的方式,进程可以将不同的操作附加到它们上。查看FreeBSD内核源代码(kern_sig.c),我发现这两个信号以相同方式处理,它们终止进程并传递给任何线程。

SA_KILL|SA_PROC,             /* SIGINT */
SA_KILL|SA_PROC,             /* SIGTERM */

10

在快速搜索了一下 sigint vs sigterm 后,看起来两者之间唯一的区别就是它们是通过键盘快捷方式还是通过显式调用 kill 来启动的。

因此,您可以例如拦截 sigint 并对其进行特殊处理,知道它可能是由键盘快捷方式发送的。也许刷新屏幕或其他操作,而不是直接退出(不推荐这样做,因为人们期望 ^C 终止程序,这只是一个示例)。

我还学到,^\ 应该发送 sigquit,我可能会开始自己使用。看起来非常有用。


4
使用kill(系统调用和实用程序)可以向任何进程发送几乎任何信号,前提是您有权限。进程无法区分信号的来源和发送者。
话虽如此,SIGINT 真正意味着信号Ctrl-C中断,而SIGTERM 是一般终端信号。没有信号被认为“更具有强制性”的概念,唯一的例外是有些信号不能被阻止或处理(根据手册,SIGKILLSIGSTOP)。
一个信号只能相对于接收进程如何处理该信号(以及该信号的默认操作是什么)而言“更具有强制性”。例如,默认情况下,SIGTERMSIGINT 都会导致终止。但是,如果您忽略SIGTERM,则它不会终止您的进程,而SIGINT 仍将终止进程。

0

除了一些信号以外,信号处理程序可以捕获各种信号,或者在接收到信号时可以修改默认行为。有关详细信息,请参阅signal(7)手册页面。


是的,但如果我不知道一个信号的“含义”,捕获该信号就毫无意义,因为我不知道在我的应用程序中该怎么做。例如GNU C解释了SIGQUIT和SIGTERM之间的区别。但它对SIGINT的信息很少:http://www.gnu.org/s/libc/manual/html_node/Termination-Signals.html - Mecki
“SIGINT”(“程序中断”)信号是在用户键入INTR字符(通常为C-c)时发送的。 "SIGINT 2 Term 来自键盘的中断" 当您按下Ctrl-C时,将发送SIGINT信号。进程通常会终止。还有什么需要提供的吗? - Ignacio Vazquez-Abrams
潜在地,程序员应该假设用户按下ctrl-c时的意图,并描述这个意图,即消息的语义。例如,HTTP规范明确指出,当用户发送GET请求时,服务器不应该假定他们希望它执行任何操作,除了返回响应。 - bdsl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接