种类:使用kill -l(查看linux信号种类)---62种
非可靠信号/非实时信号: 1~31; 可靠信号/实时信号:34~64;
产生->注册->注销->处理
产生方式:
硬件中断ctrl +z(20)/c(2)/\(3)
软件中断:
int kill(pid_t pid,int sig)给指定进程发送指定信号
int raise(int sig);给自己发送指定信号
void abort(void); 给自己发送SIGABRT信号
unsigned int alarm(unsigned int s);s秒后发送SIGLRM给自己 定时器接口
让进程知道自己收到了某个信号需要去处理,在PCB中有个未决信号集合(pending位图),每当操作系统向进程发送了一个信号,因为每个信号对应一个位图的位,就会将对应的位置为1,表示收到了这个信号,但是这样不能表示收到了几个这样相同的信号;于是操作系统还有一个sigqueue链表,每次产生一个信号,操作系统就会新建一个sigqueue节点放入这个链表中..
非可靠信号的注册:1~31号信号如果没有注册过则注册,已经注册则不会注册;
可靠信号的注册:34~64号信号,不管是否已经注册过,位图置一,向sigqueue链表中添加一个结点.
删除待处理的未决信息,一个是位图,还有一个链表(统计收到多少个相同的信号)
运行信号的处理函数,每个信号处理函数不一样,而且它是可以修改的
信号的处理方式:
sighandler_t signal(int signum, sighandler_t handler);
signum:要修改的处理方式的信号的值
handler: 函数指针 SIG_DFL-默认/SIG_IGN-忽略
其他:程序运行从用户态切换到内核态:系统调用,异常,中断
如果当前运行的是用户自己写的代码或者库函数就运行在用户态,如果是系统调用,或者中断/异常的处理就是内核态。
自定义处理方式的信号捕捉流程:
阻止当前有的未决信号的处理,有信号注册但是当前不处理,等到解除阻塞之后再处理,在pcb中有一个block阻塞信号集合,将哪个信号添加到集合中,就表示哪个信号就算到来了也暂时不处理
int sigprocmask(int how, sigset_t *new,sigset_t *old);
功能:对调用进程的阻塞信号集合进行操作
参数how
new:要添加/移除阻塞的信号集合;
old:用于接受修改前block中的信号
getchar();等待一个回车,没有回车就一直等待
sigemptyset(sigset_t *set);清空
sigaddset(sigset_t *set,int sig);添加指定信号到集合
sigfillset(sigset_t *set);添加所有信号到集合中
sigdelset(sigset_t *set,int sig)从集合中移除指定信号
sigismember(sigset_t *set,int sig);判断信号是否在集合中
在进程中有两个信号是不可被阻塞;不可被修改处理方式
SIGKILL和 SIGSTOP
那么一个进程kill杀不死的原因是什么?
1.僵尸进程2。信号被修改处理方式;3.信号被阻塞
应用:
僵尸进程的处理
(sigcb(){while(waitpid(-1,NULL,WNOHANG>0);}
signal(SSIGCHLD,SIG_IGN);//用户的显示忽略
子进程退出之后,父进程为什么没有关心到子进程退出状态?
本质上就是子进程退出之后实际上给父进程发送了一个信号-SIGCHLD,然而SIGCHLD信号的默认处理方式就是忽略,相当于父进程实际收到了通知但是什么都没做
2.所有管道读端关闭则write触发异常---SIGPIPE
作用:用于修饰变量,保持变量内存可见性
cpu处理数据时,总是保证重新从内存中加载数据进行处理
函数重入:一个函数在不同的执行流程中同时进入执行
可重入函数:一个函数就算重入也不会造成预期之外的结果
不可重入函数:一旦函数重入就有可能会出现预期之外的结果
函数的可重入与不可重入的判断基本点:
一个函数内部如果对全局数据进行了不受保护的非原子操作,则这个函数就是不可重入函数。
要使函数可重入,尽量使用局部变量,或者保护的全局变量,以及原子操作。