Linux:信号保存与处理
使用kill -l命令查看信号:
信号量和信号确实一点关系没有
信号是操作系统发出的进程与进程之间的通知于中断,是进程之间时间异步通知的一种方式
先了解同步通信:同步通信是一种比特同步通信技术,要求发收双方具有同频同相的同步时钟信号,只需在传送报文的最前面附加特定的同步字符,使发收双方建立同步,此后便在同步时钟的控制下逐位发送/接收。
优点是效率高,缺点是硬件要求高
什么叫异步通信:异步通信是指发送方在向接收方发送数据的时候可以有任意的时间间隔,没有严格的时序要求,而接收方需要一直存在,来接收数据
优点是便宜,缺点是效率低
信号量是一个计时器,表示可用资源的数量
进程产生信号的方式有四种:
通过终端按键发出信号,例如你输入ctrl c的时候可以中断进程,ctrl \是离开信号,ctrl z是暂停信号
这些信号分别对应了上图的2信号,3信号,20信号
通过系统调用函数产生信号(kill命令在实现的时候也是调用kill函数实现的,kill函数可以给指定进程发送指定的信号)
#include<signal.h>
int kill(pid_t pid,int signo);
来写一个kill函数的调用:
mykill:
#include<stdio.h>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc,char *argv[]){if(argc!=3){perror("kill false");return 1;}pid_t pid=atoi(argv[2]);int sig=atoi(argv[1]);kill(pid,sig);//啊啊啊啊,一开始写反参数的顺序了,气死了return 0;
}
myprocess.c:
#include<stdio.h>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>
void handler(int sig){printf("get a sig form myskill,sig==%d",sig);
}int main(){signal(2,handler);//signal是个系统调用函数,第一个参数是输入的信号是几,第二个参数有三种类型//此处的类型为一个函数指针,在执行该语句的时候执行一个handler函数,这个函数是要自己声明的//格式为int handler(int sig)while(1){printf("a process,pid==%d\n",getpid());fflush(stdout);sleep(1);}return 0;
}
除了kill函数还有abort函数,使当前进程接收到信号而异常终止
#include<stdlib.h>
void abort(void)
myabort.c:
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
void handler(int sig){printf("get a sig");
}
int main(){signal(3,handler);//捕获信号while(1){sleep(1);abort();//捕获之后就终止进程,因为abort就是终止}return 0;
}
还有raise,是给自己当前的进程发送信号:
#include<stdio.h>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
void handler(int sig){printf("get a sig,sig==%d\n",sig);fflush(stdout);
}
int main(){signal(3,handler);while(1){sleep(1);raise(3);//给当前进程发送信号3}return 0;
}
由软件条件产生的信号
上图的信号13是一个管道中由软件产生的信号,读端关闭,写端一直写入的时候,os会直接啥的写端进程,怎么杀掉呢?通过向目标文件发送SIGPIPE(13)信号,终止目标进程,这就叫软件条件
由硬件异常生成的信号
硬件发生异常后以某种方式被检测到并且通知到内核,内核再向进程发送适当的信号(也是设计到软件条件产生的信号)
软件条件和硬件异常的产生的信号的区别:软件条件就是操作系统和应用程序内部生成的,硬件信号是物理设备(外设)通过中断机制发送
进程递达,阻塞和捕捉
一个信号在发送给一个进程的时候需要三个阶段:这个信号我收不收?这个信号我要不要写入?我写入/或者不写入用不用?
表现出来就是一个task_struct下的三个标志位:block(要不要阻塞,对应前面的这个信号我收不收),pending(bit位的位置表示编号,不同位置代表不同的信号,对应位置的信号写入,则置为1,否则置为0),bandler(这个信号我要不要忽视=这个信号我用不用)
阻塞和忽略是不同的,阻塞是不接收这个信号,忽略是接收这个信号,写入该信号,但是不执行这个信号;也就是说信号被阻塞就不能递达,递达之后才能选择你能不能忽略
信号递达:执行信号的处理动作称为信号递达(Delivery)
信号从产生到递达(从有信号到执行信号的状态)称为信号未决(Pending)