开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情 这也是第17篇文章
关于信号的一些基本概念及思考
软中断
在早期的UNIX版本中,信号又被称为软中断。
Q:为什么会被称为软中断?
A:因为它的表现和中断类似。若进程检测到有信号到达,就中断当前程序,转向对信号事件的处理,之后才又恢复现场,继续处理原来的事件。
信号的在代码中的形式和体现是如何的?
每个信号都对应一个正整数常量,即sigal number(信号编号),这是进程之间事先约定的信息的类型。写在了头文件<signal.h>中。 以下是信号的类型:
为0时表示没有任何信号。
| 值 | 名 字 | 说 明 |
|---|---|---|
| 01 | SIGHUP | 挂起(hangup) |
| 02 | SIGINT | 中断,当用户从键盘按^c键或^break键时 |
| 03 | SIGQUIT | 退出,当用户从键盘按quit键时 |
| 04 | SIGILL | 非法指令 |
| 05 | SIGTRAP | 跟踪陷阱(trace trap),启动进程,跟踪代码的执行 |
| 06 | SIGIOT | IOT指令 |
| 07 | SIGEMT | EMT指令 |
| 08 | SIGFPE | 浮点运算溢出 |
| 09 | SIGKILL | 杀死、终止进程 |
| 10 | SIGBUS | 总线错误 |
| 11 | SIGSEGV | 段违例(segmentation violation),进程试图去访问其虚地址空间以外的位置 |
| 12 | SIGSYS | 系统调用中参数错,如系统调用号非法 |
| 13 | SIGPIPE | 向某个非读管道中写入数据 |
| 14 | SIGALRM | 闹钟。当某进程希望在某时间后接收信号时发此信号 |
| 15 | SIGTERM | 软件终止(software termination) |
| 16 | SIGUSR1 | 用户自定义信号1 |
| 17 | SIGUSR2 | 用户自定义信号2 |
| 18 | SIGCLD | 某个子进程死 |
| 19 | SIGPWR | 电源故障 |
信号与中断的异同
| 类型 | 异 | 同 |
|---|---|---|
| 信号 | 无优先级;用户态 ;响应有较大延迟 | 都是相同的异步通信方式;都可被屏蔽 |
| 中断 | 有优先级 ;核心态;响应及时 |
信号的作用机制
信号的发送
指的是将目标进程的信号域中的信号位置1。
这个域有多个bit,每个bit对应一种信号类型。一个进程可以同时接收多种不同类型的信号(因为可以对不同位置1),但是对于多个同一类型的信号,只会记住其中一个(因为对同一位重复置1没有意义)
在代码中,一个进程调用kill(pid_t pid,int sig)向别的进程发送信号。
函数的使用方法如下:
- pid==0,表示发送给同组的所有进程。
- pid>0,发送给指定的pid号的进程
- pid==-1,发送给所有用户标识符真正等于发送进程的有效用户标识号的进程,也就是 所有调用进程有权给其发送信号的进程,除了进程1(init)
信号的处理
前面提到,信号是可屏蔽的 ,如何屏蔽呢?在函数调用
void (*signal(int sig, void (*func)(int)))(int)
中,声明了进程对信号量的处理方式。
- func为0是默认值,表示执行信号内容
- func为1表示要忽略信号
- 由于func是一个指向函数的指针,所以如果这个func表示的不是一个值而是一个函数,就执行这个函数(称为捕捉(catch)一个信号)。
示例程序
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>
void waiting( );
void stop( );
int wait_mark;
void main( )
{
int p1,p2,stdout;
while((p1=fork( ))==-1); /*创建子进程p1*/
if (p1>0)
{
while((p2=fork( ))==-1); /*创建子进程p2*/
if(p2>0)
{
wait_mark=1;
signal(SIGINT,stop); /*接收到^c信号,转stop*/
waiting( );
kill(p1,16); /*向p1发软中断信号16*/
kill(p2,17); /*向p2发软中断信号17*/****
wait(0); /*同步*/
wait(0);
printf("Parent process is killed!\n");
exit(0);
}
else{
wait_mark=1;
printf("Child process 2 is killed by parent!\n");
signal(17,stop); /*接收到软中断信号17,转stop*/
waiting( );
lockf(stdout,1,0);
lockf(stdout,0,0);
exit(0);
}
}
else{
wait_mark=1;
printf("Child process 1 is killed by parent!\n");
signal(16,stop); /*接收到软中断信号16,转stop*/
waiting( );
lockf(stdout,1,0);
lockf(stdout,0,0);
exit(0);
}
}
void waiting( )
{
while(wait_mark!=0);
}
void stop( )
{
wait_mark=0;
}
输出结果: