在Linux系统中,信号(Signal)是用来通知进程的一种机制。当进程接收到信号时,它可以选择执行默认行为、忽略该信号或者捕获该信号并进行处理。
我们可以通过执行kill -l
命令来查看系统中可用的所有信号:
图 1: 列出所有信号
通常,我们使用的kill
命令实际上是用来向进程发送信号的。默认情况下,它发送的是SIGTERM
信号。而我们经常使用的kill -9 [PID]
命令,其发送的信号是SIGKILL
,这是一个强制终止进程的信号。
那么,我们如何知道进程注册了哪些信号的处理函数呢?可以通过查看SigCgt
来了解。
实验 1:捕获SIGTERM信号
步骤 1:准备示例程序
首先,我们准备一个简单的shell脚本。这个脚本通过trap
命令来捕获SIGTERM
信号,并使用名为cleanup
的函数来处理它。在没有接收到信号的时候,脚本会持续休眠。
bash
#!/bin/bash
cleanup() {
echo "Hello SIGTERM"
echo "Do something for graceful stop..."
exit
}
trap cleanup SIGTERM
while true;
do
echo "running for sleep"
sleep 1
done
将上述代码保存为test.sh
文件,并使用chmod +x test.sh
命令使其可执行。运行后如下图:
图 2: test.sh 执行的结果
步骤 2:查看 SigCgt
首先使用ps aux
命令找到该进程的PID,比如是9847,然后通过以下命令查看其SigCgt
:
shell
# 找出 PID 为 9847 的进程的 SigCgt
# 记得要把 PID 换成你的 PID
$ cat /proc/9847/status | grep -i sigcgt
SigCgt: 0000000000014002
# 转成 2 进位:
$ echo "obase=2;ibase=16;0000000000014002" | bc
10100000000000010
由于SigCgt
是以十六进制表示的,我们需要将其转换为二进制。转换后的结果是10100000000000010
。
步骤 3:查找对应的位置
图 3: SigCgt 对照
从二进制表示的SigCgt
值中,我们可以看到第15位是1,这表明我们的程序捕获了SIGTERM
信号。
实验 2:不捕捉 SIGTERM信号
步骤 1:准备示例程序
与实验1相同的示例程序,只需将trap
命令注释掉,这样就不会捕获SIGTERM
信号了。修改后,再次执行程序。
bash
#!/bin/bash
cleanup() {
echo "Hello SIGTERM"
echo "Do something for graceful stop..."
exit
}
# 把这行注解起来,也就是不再去捕捉 SIGTERM
#trap cleanup SIGTERM
while true;
do
echo "running for sleep"
sleep 1
done
步骤 2:查看 SigCgt
同样地,使用ps aux
找到进程的PID,然后查看其SigCgt
:
shell
# 找出 PID 为 9847 的进程的 SigCgt
# 记得要把 PID 换成你的 PID
$ cat /proc/10644/status | grep -i sigcgt
SigCgt: 0000000000010002
# 转成 2 进位:
$ echo "obase=2;ibase=16;0000000000010002" | bc
10000000000000010
转换为二进制后,SigCgt
的值变为10000000000000010
。
步骤 3:查找对应的位置
图 4: SigCgt 对照
通过修改示例程序中的trap
信号处理,重复上述实验,可以看到SigCgt
的值会相应地发生变化。