Linux进程信号 您所在的位置:网站首页 linux进程有三种状态 Linux进程信号

Linux进程信号

2024-06-22 10:00| 来源: 网络整理| 查看: 265

文章目录 1.Core Dump1.1ulimit命令1.2Core Dump是什么1.3Core Dump是一种事后调试1.4Core Dump调试演示1.5验证段错误是11号信号1.6为什么云服务器默认关闭Core Dump 2.信号的几种概念3.信号的保存和发送3.1信号的保存3.2信号的发送 4.信号在内核中的示意图4.1保存示意图4.2普通信号易丢失 5.sigset_t6.信号集操作函数6.1sigset_t变量设置函数6.2信号屏蔽字更改函数sigprocmask6.3读取当前未决信号集函数sigpending6.4效果演示6.5原码验证 7.信号的捕捉7.1用户态、内核态7.2信号捕捉图解7.3信号捕捉函数 sigaction 8.再次理解程序崩溃还可以进行打印9.可重入函数10.volatile11.SIGCHLD

1.Core Dump 1.1ulimit命令

ulimit命令是查看或者设置当前用户或者进程使用资源的阀值 在这里插入图片描述 如上图所示我们的core fiel的大小是0,因此需要 ulimit -c +大小,对其进行大小的设置,才能生成对应的Core Dump文件 在这里插入图片描述

1.2Core Dump是什么

当一个程序崩溃之后,操作系统会将程序奔溃前的内存之中的信息转储于磁盘之中,因为一个进程的终止,需要操作系统发送信号,而一个进程收到信号,有三种处理方式,分别为:执行默认的动作、执行自定义动作、忽略它。 所以说接收到了一个信号,并不是立即执行的,因此程序在崩溃前有时间将内存之中的信息,转存至硬盘之中

1.3Core Dump是一种事后调试

生成的core文件是二进制文件,因为core文件是给个编译器看的,方便调试,是一种事后调试(逐步逐过程为事前调试) 类似于linux的弹窗,报出错误在哪里

1.4Core Dump调试演示

在这里插入图片描述

1.5验证段错误是11号信号

在这里插入图片描述

1.6为什么云服务器默认关闭Core Dump

1.保护服务器 由2.1的图中可知,云服务器默认是关闭Core Dump的,这是因为当发生段错误时,会在磁盘之中生成临时文件,而我们的服务器出现了错误,一般都是先让服务器先恢复使用再进行错误的调式 如果服务器重启就发生错误,这样会导致生成很多临时文件,那么生成的临时文件将磁盘堆满,甚至将系统盘堆满,那么我们的系统就会出错,导致无法第一时间恢复使用

2.并不是所有的信号都需要Core Dumo 我们进程退出的时候,会有一个输出型参数status,低8位中的低7位表示退出信号,第8位表示Core Dump,如果为0则表示不需要,为1表示需要。比如我们的 kill -9号信号,系统直接终止进程,是不需要调式的

2.信号的几种概念

在这里插入图片描述

执行信号的处理动作叫做信号递达 信号从产生到递达之间的状态,称为信号未决 被阻塞的信号,产生时,将保持未决状态,当进程解除对此信号的阻塞,才会执行递达动作 阻塞和忽略是不一样的,忽略是一种处理动作,而信号只要被阻塞就不会被递达

3.信号的保存和发送 3.1信号的保存

信号的保存前提是,是否收到信号 因此我们需要记录的信息是,这个信号是谁,这个信号是否产生 而我们的实时信号有31种,因此使用一张位图可以进行保存 比特位的位置表示是那种信号,比特位为1表示该种信号产生了,为0表示该种信号没有产生 同理,我们对信号的阻塞信息,也会被保存在一张位图之中,对应的是当前信号是否被阻塞

3.2信号的发送

这张位图保存在进程的PCB之中,与其说是操作系统发出信号,不如说是操作系统向进程PCB中的位图写入信号 信号的写入是由操作系统来执行的,如何处置这个信号则是由进程来决定的

4.信号在内核中的示意图 4.1保存示意图

我们的内核之中有两张结构一样的位图,来表示当前信号是否被阻塞,和是否处于未决状态,还有一个函数指针表示处理的动作 信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达,信号标志才会被清除 在这里插入图片描述

4.2普通信号易丢失

在这里插入图片描述

5.sigset_t

每个信号的阻塞或未决都是由一个比特位来表示的,不是0就是1,因此未决和阻塞标志可以使用同一样数据类型sigset_t来进行存储 sigset_t被称为信号集,表示每个信号是有效还是无效

在阻塞状态中,有效、无效表示是否被阻塞,阻塞信号集(block表)也被叫做当前进程的信号屏蔽字 在未决状态中,有效、无效表示信号是否处于未决状态

6.信号集操作函数 6.1sigset_t变量设置函数

sigset_t是表示信号有效、无效状态的信号集,这个类型的实现是由系统来决定的,因此使用者只能调用下列函数的接口来操作sigset_t变量,而不是直接对其内部数据进行解释(比如,直接打印sigset_t类型变量,或者做位运算操作,这些都是没有意义的) 在这里插入图片描述

6.2信号屏蔽字更改函数sigprocmask

在这里插入图片描述

6.3读取当前未决信号集函数sigpending

在这里插入图片描述

6.4效果演示 void handler(int sig) { printf("i am 2 signal\n"); } void show(sigset_t *rset ) { for(int i=1;i signal(2,handler);//捕捉2号信号 sigset_t set; sigset_t oset; sigset_t rset; sigemptyset(&set);//清空当前信号集 sigaddset(&set,2);//添加2号信号 sigprocmask(SIG_BLOCK,&set,&oset);//将2号信号屏蔽 int count=0; while(1) { if(count==5)//10秒后,解除对2号信号的屏蔽 sigprocmask(SIG_SETMASK,&oset,NULL);//使用备份,恢复原来模样 sigpending(&rset);//获取当前信号集 show(&rset);//显示当前信号集 sleep(1); count++; } return 0; }

在这里插入图片描述

6.5原码验证

在这里插入图片描述

7.信号的捕捉

操作系统向进程发出信号,进程并不是立即执行信号的,而是在合适的时候,这个合适的时候是信号被递达的时候 一个信号递达,是在内核态切换回用户态时,进行信号的相关检测

7.1用户态、内核态

我们的进程是不断在用户态和内核态进行切换的,因为内核的权限高,用户态的权限低,当我们需要执行操作系统代码的时候,用户态是无法执行的,因此需要切换成内核态

内核形态和用户形态是有物理地址支持的,操作系统有且仅有一个,因此只要有进程的存在,操作系统就会存在,每个进程的虚拟空间的内核空间对应的映射关系都是同样的,都是同一份内核代码

在这里插入图片描述

7.2信号捕捉图解

在这里插入图片描述 由上述可知,一个进程是可以产生多条执行流的,比如一条当前进程代码执行流,一条信号处理执行流

7.3信号捕捉函数 sigaction

sigaction与signal是以样的,都是信号捕捉函数,只是sigaction的功能更加的丰富 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

8.再次理解程序崩溃还可以进行打印

在这里插入图片描述

9.可重入函数

两个执行流,进入同一个函数称为重入函数 在这里插入图片描述 常见不可重入函数: 1.调用malloc/free的函数,因为malloc也是用全局链表来管理堆的 2.调用了I/O函数库,标准I/O库中很多实现都以不可重入的方式使用全局数据结构 3.STL库,STL考虑的是效率问题,安全问题需要操作者自己考虑(比如迭代器失效问题,可以侧面反映)

10.volatile

volatile修饰的变量,是不可被"覆盖"的,读取变量必须读取变量真实的存储位置(不可读取缓存、寄存器等位置的值) 在这里插入图片描述

11.SIGCHLD

子进程退出,父进程可以通过阻塞或非阻塞的方式等待子进程结束,然后清理资源,但是不管是那种方式,程序的实现都是比较复杂的

有什么办法可以让父进程不用等待,又不会产生僵尸进程呢? 可以让子进程退出时,给父进程发送一个信号,父进程只需要在信号执行函数中调用wait函数清理资源,这样父进程就不必去检测子进程是否退出的问题了

1.进程终止时,会给父进程发送SIGCHLD信号 2.父进程如果通过signal或sigaction设置忽略这个信号,子进程终止时自动释放自己的资源,父进程不必再等待子进程(linux下可用,不保证其它系统上可用) 或者自定义SIGCHLD信号处理动作,调用wait等资源释放函数,也可以完成子进程资源的释放

在这里插入图片描述 在这里插入图片描述



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有