学习内容:概念,信号的生命周期(产生,注册,销毁,处理,阻塞),函数重入,volatile

1.概念

软件中断–通知一个进程发生了某个事件,打断进程当前的操作,去处理这个事件

信号一定是多种多样,且可以被识别的

种类:

kill 1–62种

1-31:非可靠信号,非实时信号

34-64:可靠信号,实习信息

生命周期:(产生,注册,销毁,处理,阻塞)

产生:Kill指令以为是杀死进程的指令,本质上是给指定的进程发送了一个终止信号

而进程接受到信号后,对信号的处理就是退出运行。

int kill( pid_t pid, int signum)-- 给指定的进程发送一个指定的信号

有些进程kill杀不死,原因?

  1. 是个僵尸进程

  1. 可能是停止状态

  1. 信号可能被阻塞,或被自定义处理

2.信号

注册

注册:让进程知道自己收到某个信号(在进程pcb中做标记)

在进程pcb中有个sigpending未决信号集合—位图(标记进程收到了某个信号)

进程的pcb中有个sigqueue链表,添加收到的信号信息链表,收到一次信号添加一个节点

未决信号:还没有被处理的信号

一个sleep进程睡眠60秒

  1. 直接kill,则会发送信号打断休眠去处理信号–退出

  1. 进程ctrl+z 进入停止,进行kill

–信号是已注册的(但是现状不处理,因为处于停止状态)

–一旦调到前台,开始运行,则开始处理信号被杀死

注销

在信号被处理之前,消除信号存在的很痕迹(主要是防止信号被重复处理)

非可靠信号的注销:删除信号的信息节点,位图置0

可靠 信号的注销:删除信号的一个信息节点,没有相同节点则位图置为0

处理

调用信号的事件处理函数

三种信号处理方式

默认处理:系统中已经预定义好的处理方式

忽略处理:空的处理方式(什么都不做)

自定义处理方式:自己定义一个处理函数,替换默认处理函数

接口:

typedef void(*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

功能:使用handler函数,替换掉signum信号当前的处理函数

意味着进程收到signum信号,则使用handler函数进行处理

handler:

SIG_DFL:信号默认的处理方式

SIG_IGN:忽略处理

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

阻塞

阻塞:信号依然会注册,但是暂时不处理(直到解除阻塞)

进程PCB中有个block阻塞信号集合,哪个信号被添加到了block阻塞集合中,就表示如果收到了也暂时不处理

如上图,先来个2号信号,pending 开始注册,注册完在处理之前检查block,发现2号位信号block为1,说明阻塞,则暂不处理;当3号信号来时,block为0,则对他在handler中进行处理,找到处理他的函数地址

阻塞接口:

int sigpromask(int how, sigset_t *set, sigset_t *old);

how:要对pcb中的信号阻塞集合进行的操作,如下:

old:将修改前block集合中的信息添加到old中(便于还原)

返回值:成功返回0,失败-1;

示例:

上述示例代码如下:

#include#include#includevoid sigcb(int no){printf("recv signal:%d\n", no);}int main(){signal(SIGINT, sigcb);//演示的信号,2号信号,非可靠信号signal(SIGRTMIN+5, sigcb);sigset_t set, old;sigemptyset(&set);sigemptyset(&old);sigfillset(&set); //阻塞set内的信号,将之前没有修改之前阻塞集合内信号保存到oldsigpromask(SIG_BLOCK, &set, &old);printf("按回车,继续运行\n");getchar();//sigpromask(SIG_UNBLOCK,&set, NULL);//解除阻塞sigpromask(SIG_SETMASK,&old, NULL);//将之前还原回去while(1){sleep(1);}//为了让程序不退出,给个睡眠return 0;}

在阻塞状态下给6个39信号,没反应,当回车之后,信号出现

应用

volatile关键字

修饰变量,保持变量内存的可见性,避免编译器过度优化

过度优化:这块特指编译器因为一个数据频繁使用,因此在进行代码优化时将数据直接加载到寄存器中,cpu处理则不需要重新从内存取数据,来提高效率,但是这种情况有时候是不合理的。

3.函数的可重入与不可重入

函数的重入:一个程序的运行,可能存在多个执行流程,如果一个函数同时在多个执行流程中,进入执行,就叫做函数的重入

可重入函数:一个函数在多个执行流程中重入之后,并不会产生一些异常或者预期之外的情况

不可重入函数:一个函数在多个执行流程中重入之后,可能会产生一些数据二义,产生预期之外的结果

上图中,main和sigcb执行的顺寻不确定,其最终结果可能是4,5,6三种,不能按照我们预期进行

当我们以后再多执行流程中使用别人封装的函数时,包括我们封装函数给别人,就要说明,这个函数是否可重用,否则就会出现问题。

不可重入的函数有几个注意点:

  1. 函数中是否涉及到对全局数据的操作

  1. 这个操作是否是原子操作