实验1
有下面的bash代码,脚本名signal.bash。
#!/bin/bash
trap 'echo INTRRUPTED BY SIGNAL INT' INT
seconds0=$(date +%s)
sleep 60s
seconds1=$(date +%s)
echo "sleeped seconds : $((seconds1 - seconds0))s"
chenglin@ubuntu-chenglin:~/shellscript/other$ time ./signal.bash
^CINTRRUPTED BY SIGNAL INT
sleeped seconds : 22s
real 0m21.427s
user 0m0.000s
sys 0m0.004s
ctrl+c后能立即停止signal.bash脚本的运行。
分析: 前台运行signal.bash脚本,其所有子程序(外部命令)和signal.bash程序在同一个进程组。而ctrl+c会发送给前台进程组所有进程INT信号。signal.bash运行后会产生两个进程,一个是signal.bash程序本身,另外一个是sleep程序(sleep是外部命令)。而sleep和signal.bash在同一个前台进程组,所以ctrl+c时,sleep程序由于处于TASK_INTERRUPTIBLE
状态(ps -axu可以看到其状态是S+)。所以会被信号INT唤醒,信号action为终止进程,自然父进程继续运行。得出运行,直到sleep被信号INT中断的睡眠时间。
实验2
现在做另外一个实验:
开两个终端,第一个终端里面运行time ./signal.bash。迅速(60s内)在第二个终端里面运行如下:
chenglin@ubuntu-chenglin:~/shellscript/powerConsumption-net$ pgrep -f signal.bash -l
25700 signal.bash
chenglin@ubuntu-chenglin:~/shellscript/powerConsumption-net$ kill -INT 25700
发现第一个终端中打印如下:
chenglin@ubuntu-chenglin:~/shellscript/other$ time ./signal.bash
INTRRUPTED BY SIGNAL INT
sleeped seconds : 60s
real 1m0.013s
user 0m0.004s
sys 0m0.004s
第二个终端不能立即停止第一个终端中signal.bash的运行。
分析: 在第二个终端是,信号INT是指定发送给signal.bash的,而不是sleep的,所以sleep没有接收到INT信号,而继续睡眠,直到指定的时间60s后,当60s后,sleep返回。主程序signal.bash此时才会处理信号。打印INTRRUPTED BY SIGNAL INT,说明处理了信号INT。
实验3
现在做第三个实验:
开两个终端,第一个终端里面运行time ./signal.bash。迅速(60s内)在第二个终端里面运行如下:
chenglin@ubuntu-chenglin:~/shellscript/powerConsumption-net$ pgrep -f sleep -l
25708 sleep
chenglin@ubuntu-chenglin:~/shellscript/powerConsumption-net$ kill -INT 25708
chenglin@ubuntu-chenglin:~/shellscript/powerConsumption-net$
发现第一个终端打印如下:
chenglin@ubuntu-chenglin:~/shellscript/other$ time ./signal.bash
sleeped seconds : 16s
real 0m15.915s
user 0m0.000s
sys 0m0.008s
分析:和实验2不同,这里是直接对sleep发送INT信号,可以直接唤醒sleep进程,并终止。但是注意到signal.bash并没有打印INTRRUPTED BY SIGNAL INT,因为信号是发给sleep进程,而不是signal.bash进程的。所以sgnal.bash进程无需处理INT信号。