Linux 信号

2025年03月17日 | 阅读 9 分钟

在 Linux 中,信号是发送给程序的中断,以表明发生了重要事件。事件可以从用户请求到无效内存访问错误。各种信号,如中断信号,意味着用户要求程序执行用户控制流中不存在的操作。

信号有两种类型

  1. 可屏蔽
  2. 不可屏蔽
    可屏蔽:- 可屏蔽信号是用户可以更改或忽略的信号,例如,Ctrl + C。
    不可屏蔽:- 不可屏蔽信号是用户无法更改或忽略的信号。不可屏蔽信号主要在用户因不可恢复的硬件错误而被发出信号时发生。
Linux Signals

Linux 计算机系统中存在处于不同状态的各种进程。所有这些进程都属于操作系统或用户应用程序。内核和这些进程之间需要一种机制来协调它们的活动。一种方法是让进程在发生任何重要事情时通知其他进程。这就是我们有信号的原因。

基本上,信号意味着单向通知。内核将信号发送给进程,发送给自身的一个进程,或发送给另一个进程。
Linux 信号源自 Unix 信号。在后来的 Linus 版本中,添加了实时信号。信号进程间是一种简单轻量级的通信形式,因此与嵌入式系统兼容。

信号的典型生命周期是什么?

信号经历三个阶段

  1. 生成
  2. 配送
  3. 处理
Linux Signals

1. 生成

信号由进程通过内核生成。任何生成信号的进程都将信号发送到特定进程。在进程号的帮助下,信号被表示,并且它不包含任何额外的数据或参数。因此,信号是轻量级的。但是,我们可以使用 POSIX 实时信号传递额外信号。可以生成信号的函数和系统调用包括 kill、sigqueue、raise、pthread_kill、killtgkill。

2. 传递

我们说过信号会一直挂起,直到它被传递。基本上,在短时间内,内核会将信号传递给进程。如果进程已阻塞信号,则进程将挂起,直到解除阻塞。

3. 处理

当信号被传递时,它会以各种方式进行处理。每个信号都包含一个默认动作,例如终止进程、忽略信号、停止进程、继续进程。对于非默认行为,可能会调用处理函数。具体会发生哪种情况是通过 sigaction 函数来声明的。

信号列表及含义

下表显示了信号列表及其含义

序号信号名称含义
1.SIGHUPHUP"挂断" 的缩写。定位要控制的终端或在控制进程死亡时挂断。当进程从终端运行且终端突然消失时,会收到此信号。
2.SIGINT当用户发送中断信号 (Ctrl + C) 时,此信号会被释放。
3.SIGQUIT当用户发送退出信号 (Ctrl + D) 时,会发出 SIGQUIT 信号。
4.SIGILL它是一个非法指令。程序中包含一些机器代码,而 CPU 无法理解这些代码。
5.SIGTRAPSIGTRAP 主要用于调试器和程序跟踪器内部。
6.SIGABRT程序调用了名为 abort() 的函数。这是一个紧急停止。
7.SIGBUSSIGBUS 是通过不正确访问内存的尝试。在内存访问中,它可能导致对齐错误。
8.SIGFPESIGFPE 是程序中发生的浮点异常。
9.SIGKILL当进程收到 SIGKILL 信号时,它必须立即退出,并且无法执行任何清理操作。
10.SIGUSR1留给程序员做他们需要的任何事情。
11.SIGSEGV尝试使用在进程中未分配的内存。这是由于数组等的末尾读取。
12.SIGUSR2留给程序员做他们需要的任何事情。
13.SIGPIPE当一个进程生成输出,该输出通过管道 ("{producer | consumer") 传输给另一个进程消费,然后消费者死亡,此时就会发送 SIGPIPE 信号给生产者。
14.SIGALRM在这种情况下,进程最终可以通过调用名为 alarm() 的函数,在未来请求操作系统进行一次 “唤醒调用”。当时间到来时,此信号包含在唤醒调用中。
15.SIGTERM这个进程显然是有人终止程序而完成的。
16.SIGCHLD此进程先前使用 fork() 函数创建一个或多个子进程。
17.SIGCONT(可与 SIGSTOP 结合阅读)
当进程通过发送 SIGSTOP 信号中断时,我们必须再发送 SIGCONT 信号以重新启动它。
18.SIGSTOP(可结合 SIGCONT 阅读。)
如果向进程发送 SIGSTOP 信号,则操作系统会停止它。它的一切状态都准备好重新启动(通过 SIGCONT),但在此之前它会获得另一个 CPU 周期。
19.SIGTSTPSIGSTP 是“终端停止”的缩写。基本上,SIGTSTOP 信号与 SIGTSTP 信号相同。当用户在终端上按下 Ctrl + Z 时,会发送 SIGTSTP 信号。
20.SIGTTINSIGTSTPSIGSTOP 之间的唯一区别是,暂停只是 SIGTSTP 的默认操作,但却是 SIGSTOP 所需的操作。此过程可能会选择以不同方式处理 SIGTSTP,但没有关于 SIGSTOP 的选项。
21.SIGTOU当后台进程尝试向其终端写入输出时。操作系统会发送 SIGTOU 信号。典型的响应基于 SIGTTIN。
22.SIGURG在网络连接的帮助下,当发送“紧急”带外数据时,操作系统会发送 SIGURG 信号。
23.SIGXCPU当进程超出其 CPU 限制时,操作系统会向其发送 SIGXCPU 信号。我们可以通过 shell 命令("ulimit -t unlimited")在运行之前取消 CPU 限制,尽管如果在 make 中达到 CPU 限制,则出现问题的可能性更大。
24.SIGXFSZ如果一个进程尝试创建一个超出文件格式限制的文件,那么操作系统会发送一个 SIGXFSZ 信号。我们也可以通过使用 shell 命令("ulimit -t unlimited")取消文件大小限制,尽管如果我们在运行之前达到文件大小限制,则出现问题的可能性更大。
25.SIGVTALRMSIGVTALRMSIGALRM 信号是相同的,只是 SIGALRM 信号在经过一定真实时间后发送,而 SIGVTALRM 在进程运行了一定时间后发送。
26.SIGPROFSIGPROG 就像 SIGVTALRMSIGALRM,而 SIGALRM 是在经过一定真实时间后发送的,SIGPROG 是在进程运行了一定时间以及代表进程运行的系统代码之后发送的。
27.SIGWINCH当进程的任何窗口大小调整时,它会使用 SIGWINCH 信号。
28.SIGIOSIGIO 也称为 SIGPOLL)。一个可以安排发送此信号的进程已准备好执行此操作,当有输入进程或输出通道已同意写入时。
29.SIGPWR电源管理服务将此信号发送给进程,以表明电源已切换到短期应急电源。
30.SIGSYS未使用

信号列表

有一个简单的方法可以列出系统支持的每个信号。我们必须在终端上输入 kill -l 命令,然后它将显示所有支持的信号列表

Linux Signals

默认动作

每个信号都关联着一个默认动作。对于一个信号,默认动作是指程序或脚本在接收到信号时执行的动作。

有各种可能的默认动作

  • 停止进程。
  • 终止进程
  • 继续一个停止的进程。
  • 忽略信号
  • 转储核心:此默认操作会生成一个名为 core 的文件,其中包含进程在收到信号时的内存映像。

发送信号

有多种方法用于向脚本或程序发送信号。对于用户来说,最基本的方法是在脚本执行时按下 INTERRUPT 键CONTROL-C

当我们输入 Ctrl+C 时,SIGINT 信号会发送给脚本,然后根据定义的默认动作,脚本会终止。

通过使用 kill 命令,我们也可以传递信号。

我们还可以使用另一种方法来传递信号,其中我们可以使用 kill 命令;以下是 kill 命令的语法

在上述 kill 命令的语法中,signal 表示要传递的信号的名称或编号,而 pid 表示要发送信号的进程 ID。例如:-

Linux Signals

上述命令将名为 hang-up 或 HUP 的信号发送给正在运行的 进程 ID 为 1001 的程序。为了向类似的进程发送 kill 信号,我们必须使用以下命令:-

Linux Signals

上述提到的 进程 ID 1001 命令将终止正在运行的进程 ID 1001

捕获信号

当我们在 shell 程序执行期间在终端上输入 Ctrl + C 或中断键时,该程序通常会立即终止,并且我们的命令提示符会返回。这可能并非总是可取的。例如,我们可能会留下一些未清理的临时文件。

捕获这些信号非常简单,下面是 trap 命令的语法

这里,command 可以是任何有效的 Linux 命令,也可以是用户定义的函数,而 signal 则包括我们需要捕获的任何信号。

在 shell 脚本中,trap 有两种基本用途

  • 清理临时文件
  • 忽略信号

空信号

发送信号的一个有趣用例是调查进程的存在。当调用 kill() 系统并将其信号参数设置为 0(即空信号)时,不会发送信号,但它可以执行错误检查以检查进程是否可以被信号。这意味着我们可以使用此过程来查看进程是否存在。发送空信号时,可能会出现以下任何响应:

  1. 如果出现 ESRCH 错误,这意味着目标进程不存在。
  2. 如果调用成功,则表示目标进程存在,并且调用者被允许向其发送信号。
  3. 如果出现 EPERM 错误,则表示目标进程存在,但我们没有足够的权限向该进程发送信号。

信号到达时会发生什么?

当信号即将传递时,根据信号的不同,会发生以下任何默认动作。

  1. 信号被忽略,即内核将其丢弃,并且对进程没有影响。(进程不知道事件仍然发生了。)
  2. 进程被终止,即异常进程终止,而不是通过 exit() 函数终止程序的正常进程终止。
  3. 生成核心转储文件,进程终止。
  4. 进程的执行被恢复或暂停。
    除了接受特定信号的默认动作外,进程还可以通过修改信号传递时发生的动作来设置信号的动作。程序可以设置以下任何动作:
    1. 必须发生默认操作。这有助于撤销信号的首次修改,使其恢复到默认值以外的状态。
    2. 信号未被注意到,而不是默认操作终止进程。
    3. 可以执行已建立的信号处理程序。信号处理程序意味着根据信号传递响应执行正确功能的自定义函数。通知内核在信号到达时必须调用处理程序函数称为安装或建立信号处理程序。除非这些信号之一具有默认处置,否则我们无法确定信号的处置以终止或转储核心。
    有两个信号 SIGSTOPSIGKILL,它们不能被阻塞、忽略或捕获。