下面我们总结一下前面几节学到的关于进程、信号和捕获的主要知识。
在 Linux 系统和其他类 Unix 或 Unix 操作系统中,信号被用于进程间的通信。
信号是一个发送到某个进程或同一进程中的特定线程的异步通知,用于通知发生的一个事件。
在 Linux 中,信号在处理异常和中断方面,扮演了极其重要的角色。
当一个事件发生时,会产生一个信号,然后内核会将事件传递到接收的进程。
运行在用户模式下的进程会接收信号。如果接收的进程正运行在内核模式,那么信号的执行只有在该进程返回到用户模式时才会开始。
当进程收到一个信号时,可能会发生以下3种情况:
在Shell命令行提示符下,输入“kill -l”命令,可以显示所有信号的信号值和相应的信号名。
由 Bash Shell 运行的非内部命令会使用 Shell 从其父进程继承的信号处理程序。
默认情况下,Shell 接收到 SIGHUP 信号后会退出。在退出之前,一个交瓦式的 Shell 会向所有的作业,不管是正在运行的还是已停止的,重新发送 SIGHUP 信号。
若要阻止 Shell 向某个特定的作业发送 SIGHUP 信号,可以使用内部命令 disown 将它从作业表中移除,或是用“disown -h”命令阻止 Shell 向特定的作业发送 SIGHUP 信号,但并不会将特定的作业从作业表中移除。
进程是运行在 Linux 中的程序的一个实例。
每当你在 Linux 中执行一个命令,它都会创建或启动一个新的进程。
有两种运行方式的进程:前台进程和后台进程。
进程可以有5种状态:不可中断休眠状态(D)、运行状态(R)、休眠状态(S)、 停止状态(T)和僵死状态(Z)。
使用 ps 命令,可以查看当前的进程;使用 pstree 命令,可以显示进程树的信息;使用 pgrep 命令,可以基于名称或其他属性查找进程。
当准备杀掉一个进程或一连串的进程时,我们的常识是从尝试发送最安全的信号开始,即 SIGTERM 信号。
如果发送一个 SIGKILL 信号到进程,将消除进程先清理而后关闭的机会,这可能导致不幸的结果。但如果一个有序地终结不管用,那么发送 SIGINT 或 SIGKILL 信号就可能是唯一的方法了。
killall 命令会发送信号到运行任何指定命令的所有进程。
使用 pkill 命令,可以通过指定进程名、用户名、组名、终端、UID、EUID 和 GID 等属性来杀掉相应的进程。pkill 命令默认也是发送 SIGTERM 信号到进程。
Bash 的内部命令 trap,让我们可以在 Shell 脚本内捕获特定的信号并对它们进行处理。
使用空字符串""或''作为 trap 的命令参熬,可以让 Shell 忽略指定的信号。
除 SIGKILL 信号以外,其他任何信号都可以被捕获并通过调用C语言函数 signal 处理。
Bash中有两个内部变量 LINENO 和 BASH_COMMAND 可以方便地在处理信号时,分别用于报告脚本当前执行的行号和脚本当前运行的命令。
使用破折号作为 trap 语句的命令参数,就可以移除指定信号的捕获。