教程:16、信号机制与信号处理

信号(signal)是Linux进程间通信的一种机制,全称为软中断信号,也被称为软中断。信号本质上是在软件层次上对硬件中断机制的一种模拟。

与其他进程间通信方式(例如管道、共享内存等)相比,信号所能传递的信息比较粗糙,只是一个整数。但正是由于传递的信息量少,信号也便于管理和使用,可以用于系统管理相关的任务,例如通知进程终结、中止或者恢复等。

每种信号用一个整型常量宏表示,以SIG开头,比如SIGCHLD、SIGINT等,它们在系统头文件<signal.h>中定义。

信号由内核(kernel)管理,产生方式多种多样:
  • 可以由内核自身产生,比如出现硬件错误、内存读取错误,分母为0的除法等,内核需要通知相应进程。
  • 也可以由其他进程产生并发送给内核,再由内核传递给目标进程。

信号传递的过程:
  • 内核中针对每一个进程都有一个表来保存信号。
  • 当内核需要将信号传递给某个进程时,就在该进程对应的表中写入信号,这样就生成了信号。
  • 当该进程由用户态陷入内核态,再次切换到用户态之前,会查看表中的信号。如果有信号,进程就会首先执行信号对应的操作,此时叫做执行信号。
  • 从生成信号到将信号传递给对应进程这段时间,信号处于等待状态。
  • 我们可以编写代码,让进程阻塞(block)某些信号,也就是让这些信号始终处于等待的状态,直到进程取消阻塞(unblock)或者忽略信号。

信号种类


信号名称数字表示说明
SIGHUP1终端挂起或控制进程终止。当用户退出Shell时,由该进程启动的所有进程都会收到这个信号,默认动作为终止进程。
SIGINT2键盘中断。当用户按下<Ctrl+C>组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为终止进程。
SIGQUIT3键盘退出键被按下。当用户按下<Ctrl+D>或<Ctrl+\>组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为退出程序。
SIGFPE8发生致命的运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等所有的算法错误。默认动作为终止进程并产生core文件。
SIGKILL9无条件终止进程。进程接收到该信号会立即终止,不进行清理和暂存工作。该信号不能被忽略、处理和阻塞,它向系统管理员提供了可以杀死任何进程的方法。
SIGALRM14定时器超时,默认动作为终止进程。
SIGTERM15

程序结束信号,可以由 kill 命令产生。与SIGKILL不同的是,SIGTERM 信号可以被阻塞和终止,以便程序在退出前可以保存工作或清理临时文件等。


过 kill -l 命令可以查看系统支持的所有信号:

上面仅是一个演示,不同的Linux发行版支持的信号可能不同。

每种信号都会有一个默认动作。默认动作就是脚本或程序接收到该信号所做出的默认操作。常见的默认动作有终止进程、退出程序、忽略信号、重启暂停的进程等,上表中也对部分默认动作进行了说明。


发送信号

有多种方式可以向程序或脚本发送信号,例如按下<Ctrl+C>组合键会发送SIGINT信号,终止当前进程。

还可以通过 kill 命令发送信号,语法为:kill -signal pid

signal为要发送的信号,可以是信号名称或数字;pid为接收信号的进程ID。例如:kill -1 1001,将SIGHUP信号发送给进程ID为1001的程序,程序会终止执行。

如,强制杀死ID为1001的进程:kill -9 1001


捕获信号

通常情况下,直接终止进程并不是我们所希望的。例如,按下<Ctrl+C>,进程被立即终止,不会清理创建的临时文件,带来系统垃圾,也不会保存正在进行的工作,导致需要重做。

可以通过编程来捕获这些信号,当终止信号出现时,可以先进行清场和保存处理,再退出程序。

用户程序可以通过C/C++等代码捕获信号,这将在Linux C编程中进行讲解,这里仅介绍如果通过Linux命令捕获信号。

过 trap 命令就可以捕获信号,语法为: trap commands signals

commands为Linux系统命令或用户自定义命令;signals为要捕获的信号,可以为信号名称或数字。

捕获到信号后,可以有三种处理:

  • 执行一段脚本来做一些处理工作,例如清理临时文件;
  • 接受(恢复)信号的默认操作;
  • 忽略当前信号。

1) 清理临时文件

脚本捕获到终止信号后一个常见的动作就是清理临时文件。例如: trap "rm -f $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 2

当用户按下<Ctrl+C>后,脚本先清理临时文件 work1$$ 和 dataout$$ 再退出。

注意:exit 命令是必须的,否则脚本捕获到信号后会继续执行而不是退出

修改上面的脚本,使接收到 SIGHUP 时进行同样的操作:trap "rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 1 2

几点注意:

  • 如果执行多个命令,需要将命令用引号包围;
  • 只有脚本执行到 trap 命令时才会捕获信号;
  • 再次接收到信号时还会执行同样的操作。

上面的脚本,执行到 trap 命令时就会替换 WORKDIR 和 $$ 的值。如果希望接收到 SIGHUP 或 SIGINT 信号时再替换其值,那么可以将命令放在单引号内,例如: trap 'rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit' 1 2

2) 忽略信号
如果 trap 命令的 commands 为空,将会忽略接收到的信号,即不做任何处理,也不执行默认动作。例如: trap '' 2

也可以同时忽略多个信号:trap '' 1 2 3 15

注意:必须被引号包围,不能写成下面的形式:trap 2

3) 恢复默认动作
如果希望改变信号的默认动作后再次恢复默认动作,那么省略 trap 命令的 commands 即可,例如: trap 1 2,将恢复SIGHUP 和 SIGINT 信号的默认动作。








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值