一、背景说明
已经记不得最早听说Linux进程之间通过信号进行通信是什么时候了,但这个东西没次听完看完之后都不是很在意,感觉和自己平时使用没什么关系。
最近突然认识到这个结论其实很重要:Linux的进程间在没有人为给他们搭建通信通道时,他们间的通信(或者叫相互作用)都是且只能是通过发送信号进行。
比如除了经典的kill命令杀除进程是给目标进程发送信号,像Ctrl+C这种能影响进程状态的命令也都是给当前进程发送信号。
二、Linux信号种类
常见linux信号如下,可使用"man 7 signal"查看更多信号说明:
Signal Name | Signal Number | Description |
---|---|---|
SIGHUP | 1 | Hang up detected on controlling terminal or death of controlling process |
SIGINT | 2 | Issued if the user sends an interrupt signal (Ctrl + C) |
SIGQUIT | 3 | Issued if the user sends a quit signal (Ctrl + D) |
SIGFPE | 8 | Issued if an illegal mathematical operation is attempted |
SIGKILL | 9 | If a process gets this signal it must quit immediately and will not perform any clean-up operations |
SIGALRM | 14 | Alarm clock signal (used for timers) |
SIGTERM | 15 | Software termination signal (sent by kill by default) |
简单的,可以使用“kill -l”列出:
三、给某进程发送Linux信号的办法
ctrl+c----向进程发出SIGINT信号
ctrl+d----向进程发出SIGQUIT信号
ctrl+z----向进程发出SIGHUP信号
kill -[s] Signal Name/Signal Number pid----向进程发送各种信号,有没有-s、是信号名还是信号值效果都是一样的。
四、Linux信号主动捕获办法
在bash中可以使用trap命令来捕抓信号,格式为"trap 捕获信号后想要执行的命令 信号"。示例如下:
# 定义一函数,该函数用作后边trap的响应函数 # 这里的意思是只有累计接收到三次Ctrl+C(亦即SIGINT信号)时才中断退出 ctrlc_count=0 function no_ctrlc() { let ctrlc_count++ echo if [[ $ctrlc_count == 1 ]]; then echo "Stop that." elif [[ $ctrlc_count == 2 ]]; then echo "Once more and I quit." else echo "That's it. I quit." exit fi } # 捕获向本进程发送的SIGINT信号,并用no_ctrlc命令(即前边定义的函数)响应 # trap命令一是不另启进程,二是能正常捕抓信号,三是不会阻塞影响正常业务 # 具体原理我还不确定,但从效果看像是另启了一个线程来捕获信号 trap no_ctrlc SIGINT # 正常的业务逻辑写在下边,我们这里随便写一个死循环 while true do echo Sleeping sleep 10 done
运行截图如下,可以看到和预期一至:业务正常运行(sleep)、Ctrl+C产生的SIGINT被捕获且捕获到三次后进程退出:
五、Linux信号忽略办法
符号 | 使用示例 | 作用 | 做不到 |
> | bash test.sh > test.log | 重定向输出 | 不占用当前控制台 不处理父进程退出信号 |
& | bash test.sh & | 不占用当前控制台 | 重定向输出 不处理父进程退出信号 |
nohup | nohup bash test.sh | 不处理交进程退出信号 | 随意重定向输出 不占用当前控制台 |
组合 | nohup bash test.sh 2>&1 > test.log |
参考: