您现在的位置是:首页 >其他 >Linux 进程信号网站首页其他
Linux 进程信号
学习内容:概念,信号的生命周期(产生,注册,销毁,处理,阻塞),函数重入,volatile
1.概念
软件中断--通知一个进程发生了某个事件,打断进程当前的操作,去处理这个事件
信号一定是多种多样,且可以被识别的
种类:
kill 1--62种
1-31:非可靠信号,非实时信号
34-64:可靠信号,实习信息
生命周期:(产生,注册,销毁,处理,阻塞)
产生:Kill指令以为是杀死进程的指令,本质上是给指定的进程发送了一个终止信号
而进程接受到信号后,对信号的处理就是退出运行。
int kill( pid_t pid, int signum) -- 给指定的进程发送一个指定的信号
有些进程kill杀不死,原因?
是个僵尸进程
可能是停止状态
信号可能被阻塞,或被自定义处理
2.信号
注册
注册:让进程知道自己收到某个信号(在进程pcb中做标记)
在进程pcb中有个sigpending未决信号集合---位图(标记进程收到了某个信号)
进程的pcb中有个sigqueue链表,添加收到的信号信息链表,收到一次信号添加一个节点
未决信号:还没有被处理的信号
一个sleep进程睡眠60秒
直接kill,则会发送信号打断休眠去处理信号--退出
进程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<stdio.h>
#include<unistd.h>
#include<signal.h>
void sigcb(int no)
{
printf("recv signal:%d
", no);
}
int main()
{
signal(SIGINT, sigcb);//演示的信号,2号信号,非可靠信号
signal(SIGRTMIN+5, sigcb);
sigset_t set, old;
sigemptyset(&set);
sigemptyset(&old);
sigfillset(&set);
//阻塞set内的信号,将之前没有修改之前阻塞集合内信号保存到old
sigpromask(SIG_BLOCK, &set, &old);
printf("按回车,继续运行
");
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三种,不能按照我们预期进行
当我们以后再多执行流程中使用别人封装的函数时,包括我们封装函数给别人,就要说明,这个函数是否可重用,否则就会出现问题。
不可重入的函数有几个注意点:
函数中是否涉及到对全局数据的操作
这个操作是否是原子操作