当前位置:   article > 正文

Linux进程信号~详解_singnal 33 退出

singnal 33 退出

一.信号的概念

信号是进程之间事件异步通知的一种方式,属于软中断
告诉有这样一个信号,但是这个信号的具体处理方式以及什么时候处理由进程决定,所以是软中断。

二.信号的种类

kill —l
  • 1

可以罗列出所有信号(总共定义了62个信号)
在这里插入图片描述
没有32,33号信号

  • 非实时信号(又称非可靠信号)
    特点:信号可能会丢失 1~31

  • 实时信号(又称可靠信号)
    特点:信号不会丢失 33~64

三.信号的产生

1.硬件产生

kill命令向进程发送信号kill -[信号值] [pid]

  • ctrl +c :2号信号 SIGINT
    键盘按下ctrl +c 结束一个进程的时候,其实是进程收到了2号信号。2号信号导致进程的退出
  • ctrl +z:20号信号SIGTSTP
    在这里插入图片描述在这里插入图片描述
    使用ctrl +z会使一个程序进入暂停状态T;
  • ctrl +|
    在这里插入图片描述

2.软件产生

  • kill函数int kill(pid_t pid,int sig);
    pid:进程号,要给哪个进程发送信号,则填写哪个进程的进程号
    sig:要发送信号的值
    在这里插入图片描述

  • raiseint raise(int sig);
    谁调用则给谁发送信号。该函数的实现也是调用kill函数

int raise(int sig){
	return kill(gitpid(),sig);
}
  • 1
  • 2
  • 3

在这里插入图片描述

3.扩展:崩溃程序收到的信号

  • 引用空指针,野指针,垂悬指针(收到11号信号)
  • 内存访问越界(收到11号信号)
  • 除0(收到8号信号)
  • double free(收到6号信号)

我们在C/C++当中除零,内存越界等异常,在系统层面上,是被当成信号处理的。

四.信号的处理方式

man 7 signal  查看
  • 1

在这里插入图片描述

1.默认处理方式

SIG_DFL:操作系统当中已经定义信号的处理方式了
2–>终止程序
11—>终止程序,并且产生核心转储文件

2.忽略处理方式

SIG_IGN:该信号为忽略处理
进程收到忽略处理信号后,不进行处理

SIGCHLD 17号信号

子进程先于父进程退出,子进程退出的时候会给父进程发送SIGCHLD,而父进程接收到这个信号后,是忽略处理的,导致父进程没有回收到子进程的退出状态信息,从而子进程变成僵尸进程。

3.自定义处理方式

程序员也可以更改信号的处理方式,定义一个函数,当进程收到该信号的时候,调用自己写的函数

五.信号的注册

一个信号收一个信号的过程叫做信号的注册
信号的注册和信号的注销不是一个过程,是两个独立的过程

内核当中信号注册位图和sigqueue 队列的了解
在这里插入图片描述
操作系统内部并没有将sig[] 当做数组使用,而是当做位图使用
在这里插入图片描述
总结:

  1. 信号注册时位图更改为1,添加sigqueue节点和sigqueue队列
  2. 信号注册时,会将信号对应的比特位从0修改为1,表示当前进程收到了该信号
  3. 需要在sigqueue队列中添加sigqueue节点,队列在操作系统内核中的本质是一个双向链表(先进先出

两种信号注册的区别

  • 非实时信号注册
    第一次注册:修改sig位图(从0到1),修改sigqueue队列
    第二次注册相同信号:修改sig位图(从1到1),并不会添加sigqueue节点
  • 非实时信号注册
    第一次注册:修改sig位图(从0到1),修改sigqueue队列
    第二次注册相同信号:修改sig位图(从1到1),添加sigqueue节点到sigqueue队列当中

六.信号的注销

  • 非实时信号
    将信号对应的sig位图当中的比特位由1改为0
    将对应信号的sigqueue节点进行出队操作

  • 实时信号
    将对应的信号的sigqueue节点进行出队操作
    判断sigqueue队列当中是否还有相同信号的sigqueue节点
    有:则比特位不变 没有:比特位由1改为0

七.信号的自定义处理方式

程序员自己定义某一个信号的处理方式

1.实现函数

函数sighandler_t signal(int signum,sighandler_t handler);

  • signum:信号值
  • handler:更改为的函数处理,接收一个函数地址,函数指针typedef void(*sighandler_t)(int);
    注意:
    在调用singnal函数的时候,给第二个参数传递函数地址的时候并没有调用传递的函数,而是等到进程收到某个信号的时候,才回调刚刚注册的函数。
    9号信号SIGKILL(强杀)不能被自定义处理。

函数int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

  • signum:信号值
  • act:将信号的处理方式改为act
  • oldact:原来信号的处理方式
#include<stdio.h>
#include<unistd.h>
#include<signal.h>


struct sigaction oldact;
 
void sigcallback(int sig)
{
    printf("sig num is %d\n",sig);
    sigaction(2,&oldact,NULL);
}


int main(){
    //调用sigaction函数,自定义2号信号的处理方式
    //定义struct sigaction 机构体对象
    struct sigaction act;
    act.sa_handler=sigcallback;
    //将act.sa_mask内部清0,防止后续误导进程收到某些信号
     sigemptyset(&act.sa_mask);

     sigaction(2,&act,&oldact);

     while(1){
    sleep(1);
     }
return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

主函数中调用sigaction将2号信号的处理方式改为调用sigcallback,在sigcallback函数中重新将2号信号处理方式改回来
现象:运行程序第一次按下crrl+c运行sigcallback函数内部代码,第二次按下结束进程
在这里插入图片描述

2.原理:内核中的代码

在这里插入图片描述

八.信号的捕捉流程

1.过程

在这里插入图片描述

2.信号的处理时机

当从内核态切换回用户态的时候,会调用do_signal函数处理信号
do_signal:判断当前信号是否被阻塞
有:处理该信号(信号的处理方式:默认,忽略,自定义)
没有:直接返回用户态

3.不同的处理方式

默认,忽略:直接在内核中就结束处理
自定义处理:

  • 执行用户自定义的处理函数(用户空间)
  • 执行sigreturn()再次回到操作系统内核(内核空间)
  • 再次调用 会调回do_signal函数处理信号
  • 调用sys_sigreturn函数回到用户态,继续执行代码

4.常见进入内核的方式

  • 调用系统调用函数
  • 内存访问越界,访问空指针
  • 调用库函数

九.信号的阻塞

信号的阻塞并不会影响信号的注册,而是在进程收到信号的时候,由于阻塞,暂时不处理该信号

1.内核代码

  struct task_struct{
.........
        sigset_t blocked;(位图)
........
}
  • 1
  • 2
  • 3
  • 4
  • 5

当需要阻塞一个信号的时候,将信号对应的比特位设置为1
0:不阻塞
1:阻塞

当加上信号阻塞后,理解信号的处理

  • 进入内核,返回之前,会调用do_signal函数处理该信号
  • 有信号要处理的时候,先判断信号是否阻塞,有阻塞则不处理,无阻塞则处理信号

2.函数接口

函数int sigprocmask(int how,sigset_t *set, sigset_t *oldset);

  • how:想让sigprocmask做什么事情
    SIG_BLOCK:设置某个信号进入阻塞状态
    SIG_UNBLOCK:设置某个信号进入非阻塞状态
    SIG_SETMASK:用第二个参数‘set’,替换原理的阻塞位图
  • set:设置新的阻塞位图
  • oldset:原理老的阻塞位图

原理解析:

  • 当how为SIG_BLOCK时,函数会根据set,计算新的阻塞位图方式为block(new)=block(old) | set
  • 当how为SIG_UNBLOCK时block(new)=block(old) & ~set
  • 当how为SIG_SETMASK时block(new)=set

9号信号和19号信号不能被阻塞

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/781708
推荐阅读
相关标签
  

闽ICP备14008679号