如果需要降低系统负载或是重启系统(如果进程行为失常,开始耗费过多资源),就得杀死进程。作为一种进程间通信机制,信号可以中断进程运行并强迫进程执行某些操作。这些操作就包括以受控的方式终止进程或立刻终止进程。
10.4.1 预备知识
信号能够中断正在运行的程序。当进程接收到一个信号时,它会执行对应的信号处理程序(signal handler)作为响应。编译型的应用程序使用系统调用kill生成信号。在命令行(或是shell脚本)中是通过kill命令来实现的。trap命令可以在脚本中用来处理所接收的信号。
每个信号都有对应的名字以及整数值。SIGKILL``(9)信号会立即终止进程。Ctrl+C会发送信号中断任务Ctrl+Z会发送信号将任务置入后台。
①
Ctrl+C发送的是SIGINT信号。它和SIGKILL信号的区别在于后者不能被捕获,也不能被忽略。
10.4.2 实战演练
(1) kill -l 命令可以列出所有可用的信号
$ kill -lSIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP...
(2) 终止进程
$ kill PROCESS_ID_LISTkill 命令默认发送 SIGTERM 信号。进程 ID 列表中使用空格来分隔各个进程 ID。
(3) 选项 -s 可以指定发送给进程的信号:
$ kill -s SIGNAL PID
参数 SIGNAL 可以是信号名或编号。尽管信号的用途各种各样,但常用的其实也就是那么几个。
- SIGHUP 1:对控制进程或终端的结束进行挂起检测(hangup detection)。
- SIGINT 2:当按下
Ctrl+C时发送该信号。 - SIGKILL 9:用于强行杀死进程。
- SIGTERM 15:默认用于终止进程。
- SIGTSTP 20:当按下
Ctrl+Z时发送该信号。
(4) SIGTERM 选项
我们经常需要强行杀死进程,这样做的时候要小心。这种做法立刻生效,根本没有机会保存数据或执行通常的清理工作。应该先尝试使用 SIGTERM,将SIGKILL留作最后一招:
$ kill -s SIGKILL PROCESS_ID
也可以使用下面的命令执行清理操作:
$ kill -9 PROCESS_ID
10.4.3 补充内容
Linux中还有其他一些可以发送信号或终止进程的命令。
kill 命令系列
kill命令以进程ID作为参数。killall命令可以通过名字来终止进程:
$ killall process_name
选项-s可以指定要发送的信号。killall默认发送SIGTERM信号:
$ killall -s SIGNAL process_name
选项-9可以依照名字强行杀死进程:
$ killall -9 process_name
例如:
$ killall -9 gedit
选项-u可以指定进程所属用户:
$ killall -u USERNAME process_name
如果需要在杀死进程前进行确认,可以使用killall的-I选项。
pkill命令和kill命令类似,不过默认情况下pkill接受的是进程名,而非进程ID:
$ pkill process_name$ pkill -s SIGNAL process_name
SIGNAL是信号编号。pkill不支持信号名,该命令的很多选项和kill一样。要了解更多详细信息,请参阅pkill的命令手册。
捕获并响应信号
设计良好的程序在接收到SIGTERM信号时会保存好数据,然后放心地结束(shut down cleanly)。trap命令在脚本中用来为信号分配信号处理程序。一旦使用trap将某个函数分配给一个信号,那么当脚本运行收到该信号时,就会执行相应的函数。
命令语法如下:
trap 'signal_handler_function_name' SIGNAL_LIST
SIGNAL_LIST以空格分隔,它可以是信号编号或信号名。
下面是一个能够响应信号SIGINT的shell脚本:
#/bin/bash#文件名:sighandle.sh#用途:信号处理程序function handler(){echo Hey, received signal : SIGINT}# $$是一个特殊变量,它可以返回当前进程/脚本的进程IDecho My process ID is $$#handler是信号SIGINT的信号处理程序的名称trap 'handler' SIGINTwhile true;dosleep 1done
[root@dev workspace]# ls -al sighandle.sh-rwxr-xr-x 1 root root 331 Jan 28 21:59 sighandle.sh[root@dev workspace]# ./sighandle.shMy process ID is 109^CHey, received signal : SIGINT
在终端中运行该脚本。当脚本运行时,如果按Ctrl+C,就会显示一条消息,这是通过执行与信号关联的信号处理程序实现的。Ctrl+C会发出一个SIGINT信号。通过使用一个无限循环while来保持进程运行。这样就可以使它能够响应另一个进程以异步方式发送的信号。用来保持进程一直处于活动状态的循环通常称为事件循环(event loop)。如果给出了脚本的进程ID,我们可以用kill命令向其发送信号:
$ kill -s SIGINT PROCESS_ID
$ kill -s SIGINT 109

脚本sighandle.sh会在运行时输出自己的进程ID,或者也可以用ps命令找出它的进程ID。如果没有为信号指定信号处理程序,那么将会调用由操作系统默认分配的信号处理程序。一般来说,按下Ctrl+C会终止程序,因为这是操作系统提供的处理程序的默认行为。不过这里我们自定义的信号处理程序覆盖了默认的信号处理程序。
我们能够通过trap命令为任何可用的信号(kill -l)定义处理程序。一个信号处理程序也可以处理多个信号。
