Linux-信号(重入,volatile关键字)

种类:使用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链表中添加一个结点.

注销

删除待处理的未决信息,一个是位图,还有一个链表(统计收到多少个相同的信号)

  • 对于非可靠信息:因为它不会重复注册,链表中最多有一个节点,因此删除一个节点,并且对位图置0;
  • 对于可靠信息:因为可靠信号有可能存在多个相同的信号节点,因此删除一个节点后,若还有相同节点则位图不变,否则置零.

处理

运行信号的处理函数,每个信号处理函数不一样,而且它是可以修改的

信号的处理方式:

  • 默认处理方式---系统针对每个信号定义好的处理方式
  • 忽略处理方式---就是忽略,收到信号什么都不做
  • 自定义处理方式---用户自定义信号处理函数然后进行替换
sighandler_t signal(int signum, sighandler_t handler);

signum:要修改的处理方式的信号的值

handler: 函数指针 SIG_DFL-默认/SIG_IGN-忽略

其他:程序运行从用户态切换到内核态:系统调用,异常,中断

如果当前运行的是用户自己写的代码或者库函数就运行在用户态,如果是系统调用,或者中断/异常的处理就是内核态。

自定义处理方式的信号捕捉流程:

  1. 程序运行因为中断/异常/系统调用从用户态切换到内核态
  2. 完成内核处理功能后,再返回用户态主控流程之前检测是否有信号待处理,有则处理信号
  3. 默认和忽略在内核中完成,自定义需要在用户态运行
  4. 信号的自定义处理函数运行完毕,返回内核态

信号的阻塞

阻止当前有的未决信号的处理,有信号注册但是当前不处理,等到解除阻塞之后再处理,在pcb中有一个block阻塞信号集合,将哪个信号添加到集合中,就表示哪个信号就算到来了也暂时不处理

int sigprocmask(int how, sigset_t *new,sigset_t *old);
功能:对调用进程的阻塞信号集合进行操作

参数how

  1. SIG_BLOCK block |= new 向block集合添加new信号
  2. SIG_UNBLOCK block &= ~new 从block中移除new中信号
  3. SIG_SETMASK block = new 将new设置为block

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

volatile 

作用:用于修饰变量,保持变量内存可见性

cpu处理数据时,总是保证重新从内存中加载数据进行处理

函数重入

函数重入:一个函数在不同的执行流程中同时进入执行

        可重入函数:一个函数就算重入也不会造成预期之外的结果

        不可重入函数:一旦函数重入就有可能会出现预期之外的结果

函数的可重入与不可重入的判断基本点:

一个函数内部如果对全局数据进行了不受保护的非原子操作,则这个函数就是不可重入函数。

要使函数可重入,尽量使用局部变量,或者保护的全局变量,以及原子操作。

你可能感兴趣的:(Linux操作系统,linux,运维,服务器)