SIGINT 与其他终止信号如 SIGTERM、 SIGQUIT 和 SIGKILL 有什么关系?

在 POSIX 系统中,终止信号通常有以下顺序(根据许多 MAN 页和 POSIX 规范) :

  1. SIGTERM -礼貌地请求进程终止。它将优雅地终止,清除所有资源(文件、套接字、子进程等) ,删除临时文件等等。

  2. SIGQUIT -更有力的请求。它会不合时宜地终止,仍然清理绝对需要清理的资源,但可能不会删除临时文件,可能会在某处写入调试信息; 在某些系统上也会写入一个核心转储(无论信号是否被应用程序捕获)。

  3. SIGKILL -最强烈的请求。进程甚至不需要执行任何操作,但系统将清理进程,不管它是否喜欢这样做。很可能已经编写了核心转储。

SIGINT怎么会出现在那张照片里?当用户点击 CRTL+C时,一个 CLI 进程通常被 SIGINT终止,但是一个后台进程也可以使用 KILL实用程序被 SIGINT终止。我在规范或头文件中看不到的是,SIGINT是否比 SIGTERM更强或更弱,或者 SIGINTSIGTERM之间有什么区别。

更新:

到目前为止,我发现对终止信号最好的描述是在 GNU LBC 文档中。它很好地解释了 SIGTERM 和 SIGQUIT 之间的预期差异。

它说的是 SIGTERM:

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

上面写着 SIGQUIT:

[ ... ]并在终止进程时产生一个内核转储,就像程序错误信号一样。 您可以将其视为用户“检测到”的程序错误条件 在处理 SIGQUIT 时,最好省略某些类型的清理 创建临时文件时,它应该通过删除临时文件来处理其他终止请求 但是 SIGQUIT 最好不要删除它们,这样用户就可以在 与堆芯倾倒物相连接。

SIGHUP也被很好地解释了。SIGHUP 实际上并不是一个终止信号,它只是意味着与用户的“连接”已经丢失,所以应用程序不能期望用户读取任何进一步的输出(例如 stdout/stderr 输出) ,也不再期望用户输入。对于大多数应用程序来说,这意味着他们最好退出。理论上,当接收到 SIGHUP 并作为后台进程运行时,应用程序还可以决定进入守护进程模式,将输出写入已配置的日志文件。对于大多数已经在后台运行的守护进程来说,SIGHUP 通常意味着它们应该重新检查它们的配置文件,因此在编辑配置文件之后将其发送到后台进程。

然而,在这个页面上没有对 SIGINT 的有用解释,除了它是由 CRTL + C 发送的。有什么原因可以解释为什么对 SIGINT 的处理方式不同于 SIGTERM?如果是这样的话,原因是什么? 操作会有什么不同?

70237 次浏览

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

使用 kill(系统调用和实用程序) ,您可以向任何进程发送几乎任何信号,只要您得到了许可。一个过程无法区分信号是如何产生的以及是谁发送的。

也就是说,SIGINT实际上是用来发送 Ctrl-C中断的信号,而 SIGTERM是一般的终端信号。没有信号是“更有力”的概念,唯一的例外是有信号不能被阻塞或处理(SIGKILLSIGSTOP,根据手册页)。

在接收进程如何处理信号(以及该信号的默认动作是什么)方面,信号只能比另一个信号“更有力”。例如,默认情况下,SIGTERMSIGINT都会导致终止。但是如果忽略 SIGTERM,那么它将不会终止您的进程,而 SIGINT仍然会。

正如暗尘指出,许多信号有相同的结果,但进程可以附加不同的行动,他们通过区分每个信号是如何产生的。查看 FreeBSD 内核源代码(kern _ sig.c) ,我发现这两个信号是以相同的方式处理的,它们终止进程并传递给任何线程。

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

SIGTERMSIGKILL用于通用的 “终止这个过程”请求。SIGTERM(默认情况下)和 SIGKILL(总是)将导致进程终止。SIGTERM可能被进程捕获(例如,如果它想的话,它可以自己进行清理) ,甚至完全被忽略; 但是 SIGKILL不能被捕获或忽略。

SIGINTSIGQUIT是专门为来自终端的请求而设计的: 可以指定特定的输入字符来生成这些信号(取决于终端控制设置)。SIGINT的默认操作与 SIGTERM的默认操作和 SIGKILL的不可更改操作是同一类型的进程终止; SIGQUIT的默认操作也是进程终止,但可能会出现额外的实现定义的操作,比如生成核心转储。如果需要,进程可以捕获或忽略这两种情况。

正如您所说的,SIGHUP用于指示终端连接已丢失,而不是终止信号本身。但是,同样,SIGHUP的默认操作(如果进程没有捕获或忽略它)是以与 SIGTERM等相同的方式终止进程。

POSIXsignal.h的定义中有一个表,其中列出了各种信号及其默认操作和用途,而 通用终端接口章包含了关于终端相关信号的更多细节。

在谷歌上快速搜索了一下 Sigint 对 sigterm之后,似乎两者之间唯一的区别在于它是由一个快捷键发起的,还是由一个对 kill的明确调用发起的。

因此,例如,你可以拦截信号,并对其进行特殊处理,因为你知道它很可能是由快捷键发送的。也许刷新屏幕或其他东西,而不是死(不建议,因为人们期望 ^C杀死程序,只是一个例子)。

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

man 7 signal

这是 Linux 手册页项目的一个方便的非规范的页面,您通常希望查看这个页面以获得 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

由于 SIGQUIT 具有动作 Core和 SIGINT Term,因此它总结了区分 SIGQUIT 和 SIGQUIT 的信号 Action

这些行动记录在同一份文件中:

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草案 N1256的“7.14信号处理”章节中有描述:

  • 交互式注意信号接收
  • 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 init

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

这是 最小的具体例子

内核发送的信号