进程信号

  • 信号的概念
  • 信号的产生
  • 信号的注册
    • 非可靠信号的注册
    • 可靠信号的注册
  • 信号的注销
    • 非可靠信号的注销
    • 可靠信号的注销
  • 信号的处理方式
    • 默认处理方式
    • 忽略处理方式
    • 自定义处理方式
  • 信号的捕捉流程
  • 信号的阻塞

信号的概念

信号是一个软件中断

信号的产生

硬件产生

ctrl + c:SIGINT(2)
ctrl + z:SIGTSTP(20)
ctrl + |:SIGQUIT(3)

操作系统对信号的处理动作:man 7 signal 查看

term:终止
ign:忽略
core:终止并产生coredump文件
stop:停止
cont:继续运行

如果产生下面的错误可以去看看这个博客,下载后就可以解决了
https://blog.csdn.net/qq_28779503/article/details/54893745

信号具体的信息:信号的名称+信号的值(整数)+action+描述

软件产生

kill命令:kill [pid] 可以终止一个进程kill -[num] [pid] 给进程号为 pid 的进程发送一个信号值为 num 的信号kill函数:int kill(pid_t pid, int sig);功能:给 pid 进程发送 sig 信号需要包下面的头文件:#include <signal.h>
  1 #include <stdio.h>2 #include <unistd.h>3 #include <signal.h> 4                                       5 int main()                            6 {                                     7   printf("-----begin-----\n");8   kill(getpid(), 9); 9   printf("------end------\n");        10   return 0;                           11 }

raise函数:int raise(int sig);功能:谁调用给谁发送 sig 信号
  1 #include <stdio.h>2 #include <unistd.h>3 #include <signal.h>4 5 int main()6 {7   printf("-----begin-----\n");8   raise(2);9   kill(getpid(), 9);10   printf("------end------\n");11   return 0;12 }


说明此时在 raise 就结束掉了,并没有走到 kill

信号的种类:

目前linux的信号数量为62个,分为两种类型1、非实时信号(非可靠信号)    1~31特点:有可能信号会丢失2、实时信号(可靠信号)    34~63特点:信号不会丢失

信号的注册

注册:一个进程收到一个信号的过程称为注册

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

信号的注册分为两种情况:非可靠信号的注册和可靠信号的注册

1、在操作系统内核“struct task_struct”结构体内部有一个变量:“struct sigpending pengding”2、内核定义的结构体“struct sigpending”当中有两个变量一个是内核定义的双向链表第二个是:sigset_t signal3、内核定义的类型“sigset_t”为一个结构体,在结构体内部有一个变量,该变量为一个数组(无符号长整型数组)unsigned long sig[_NSIG_WORDS];信号的注册本质上就是在使用sig数组,但是并不是按照数组类型的方式在使用,而是按照位图(比特位)的方式在使用:eg:某个信号注册,则将某个信号队友的比特位置为1sig数组的比特位远远大于62,剩下的比特位为保留位struct sigpending ⇒ sigset_t signal ⇒ sig[xxx]
一般在信号注册的时候,称之为操作sig位图,即sig[xxx]内核当中对于注册的时候,还有一个sigqueue队列,信号的注册逻辑为将信号队友的sig位图当中的比特位置为1,并且在sigqueue队列当中
添加一个sigqueue节点通过注册第一个信号两次,来区分可靠信号和非可靠信号的注册逻辑

非可靠信号的注册

第一次:1、更改信号对应在sig位图当中的比特位(0 --> 1)2、在sigqueue队列当中添加sigqueue节点第二次:1、更改信号对应的sig位图当中的比特位(1 --> 1)2、对于第二次的信号,不添加sigqueue节点到sigqueue队列当中如果有多次同一个信号来注册,对于非可靠信号而言,只会添加一次sigqueue节点,换言之,只注册了一次

可靠信号的注册

第一次:1、更改信号对应在sig位图当中的比特位(0 --> 1)2、在sigqueue队列当中添加sigqueue节点第二次:1、更改信号对应的sig位图当中的比特位(1 --> 1)2、再次在sigqueue队列当中添加sigqueue节点如果有多次同一个信号来注册,对于可靠信号而言,会添加多次sigqueue节点,即注册多次

信号的注销

非可靠信号的注销

1、将信号对应到sig位图当中的比特位置为0
2、将对应的非可靠信号的sigqueue节点进行出队操作

可靠信号的注销

1、先将可靠信号对应的sigqueue节点进行出队操作
2、判断sigqueue队列当中是否有同类的可靠信号的sigqueue节点如果有:不会将sig位图当中对于的比特位置为0如果没有:将sig位图当中对于的比特位置为0

信号的处理方式

默认处理方式

在操作系统内核当中已经定义好了

宏:SIG_DFL

忽略处理方式

操作系统定义进程收到某个信号后忽略掉(进程即使收到了某个信号,进程也不会做任何事情)

宏:SIG_IGN

僵尸进程:子进程先于父进程退出,子进程会向父进程发送SIGCHLD信号,父进程对SIGCHLD信号是忽略处理的,所以父进程并不会做任何事情,导致子进程的资源没有进程进行回收,从而子进程变成僵尸进程

自定义处理方式

程序员可以定义某个信号的处理方式

函数

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signum:待要更改的信号的值
handler:函数指针,接收一个函数的地址,这个函数没有返回值,有一个int类型的参数自定义signum这个信号的处理方式,定义为handler这个函数指针保存的函数地址对应的函数
换句话说,当进程收到signum这个信号的时候,就会调用handler当中保存的函数
1 #include <stdio.h>2 #include <unistd.h>3 #include <signal.h>4 5 void sigcallback(int signo)6 {7   printf("i am sigcallback, signo is %d\n", signo);8 }9 10 int main()11 {12   signal(SIGINT, sigcallback);13 14   while(1)15   {16     printf("i am main\n");17     sleep(1);                   18   }                             19   return 0;                     20 }

signal函数向内核注册了一个信号的处理函数,调用signal函数的时候,并没有调用注册的函数(注册的函数在进程收到信号之后才调用),
这种方式被称为“回调”
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);struct sigaction {void     (*sa_handler)(int);//默认的信号处理函数保存的函数指针void     (*sa_sigaction)(int, siginfo_t *, void *);//↑函数指针,要配合sa_flags一起使用,当sa_flags当中的值为SA_SIGINFO的时候,//信号处理是按照“sa_sigaction”当中保存的函数地址来处理的sigset_t   sa_mask;//当进程在处理某一个信号时,有可能还会收到其他的信号,此时其他的信号暂时存放在sa_mask中int        sa_flags;void     (*sa_restorer)(void);//保留字段};
signum:待要自定义处理的信号
act:要将信号处理方式更改为act
oldact:原来的处理方式
  1 #include <stdio.h>2 #include <unistd.h>3 #include <signal.h>4 5 void sigcallback(int signo)6 {7   printf("i am sigcallback, signo is %d\n", signo);8 }9 10 int main()11 {12   struct sigaction sa;13   sa.sa_handler = sigcallback;14   //int sigemptyset(sigset_t *set);15   sigemptyset(&sa.sa_mask);16   sa.sa_flags = 0;//默认就等于017 18   sigaction(2, &sa, NULL);19 20   while(1)21   {22     printf("i am main\n");23     sleep(1);24   }25 26   return 0;27 }

信号的捕捉流程

信号注册在进程的PCB当中,是操作系统和PCB打交道

捕捉流程指的是信号什么时候进行处理

信号的处理是在内核态完成的

1、从内核态切换回用户态的时候,一定会调用do_signal函数,来处理进程收到的信号①sig位图当中有信号注册,则执行信号注销的逻辑②sig位图当中没有信号注册,则直接返回用户态2、处理信号(信号注销)①默认处理方式(直接在操作系统内核的代码中就完成了)②忽略处理方式(直接在操作系统内核的代码中就完成了)③自定义处理方式(调用程序员自己定义的代码)3、自定义处理方式①在用户态执行程序员自己定义的函数②调用sigreturn函数再次回到操作系统内核③再次调用do_signal函数判断是否有信号注册,如果有,返回到处理信号④调用sys_sigreturn函数回到用户态继续去执行代码

信号的阻塞

信号的阻塞,不会影响信号的注册

接口:

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
how:想让sigprocmask函数做什么SIG_BLOCK:设置某个信号为阻塞状态SIG_UNBLOCK:设置信号为非阻塞状态SIG_SETMASK:设置新的block位图
set:使用set去设置block位图SIG_BLOCK:block(new) = block(old)| seteg:block(old):0101 0000set:0000 1000==》 0101 1000SIG_UNBLOCK:block(new) = block(old)& (~set)eg:block(old):0101 0000&~set:1011 1111==》  0001 0000SIG_SETMASK:block(new) = set

进程信号(信号、信号的注册与注销、信号的处理方式)相关推荐

  1. 默认子进程与父进程属于同一个进程组,所以注意对接受到的信号的处理方式

    fork()时,子进程继承了父进程的进程组ID,所以父子进程默认属于同一个进程组,又因为同一个进程组的进程可以接受来自同一终端的各种信号所以当希望用键盘发送信号(如按下Ctrl+C)时,父子进程对接收 ...

  2. C语言 信号集回调函数 避免子进程在信号回调注册完成之前全部结束

    // ..使用内存映射可以拷贝文件 /* 对原始文件进行内存映射 创建一个新文件 把新文件的数据拷贝映射到内存中 通过内存拷贝将第一个文件的内存映射区拷贝到第二个文件的内存映射区 释放资源 */// ...

  3. 2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,

     1信号产生原因 2.进程处理信号行为 manpage里信号3中处理方式: SIG_IGN SIG_DFL                                            默 ...

  4. 进程间通讯(IPC)(有信号捕捉函数)

    1.IPC(Internal Processes Communication) 进程间通讯--->实际上数据的交换. 通过全局变量的方式实现不了进程间通讯 因为进程内存空间,都是相互独立的,不能 ...

  5. linux线程关闭信号,Linux/UNIX用同步方法处理异步信号

    一. 前言 Linux/UNIX进程信号处理复杂易出错,而用在多线程中就更加复杂脆弱,这里不探讨相关历史渊源,只给出一种在实践中简单可靠的信号处理方式.后文讨论的线程模型是POSIX thread(p ...

  6. linux c语言 信号,linux下基于C语言的信号编程实例

    搜索热词 本文实例讲述了linux下基于C语言的信号编程方法.分享给大家供大家参考.具体如下: #include #include #include #include #include void si ...

  7. linux 信号没有被处理方法,[计算机]Linux 信号signal处理机制.doc

    [计算机]Linux 信号signal处理机制 Linux 信号signal处理机制 信号是Linux编程中非常重要的部分,本文将详细介绍信号机制的基本概念.Linux对信号机制的大致实现方法.如何使 ...

  8. sigquit信号默认忽略吗_linux下的信号列表

    我们运行如下命令,可看到Linux支持的信号列表: $ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7 ...

  9. golang 监听服务的信号,实现平滑启动,linux信号说明

    监听服务的信号,实现平滑启动,linux信号说明 package mainimport ("context""fmt""golang.org/x/sy ...

最新文章

  1. android 响应点击事件,Android响应事件onClick方法的五种实现方式小结
  2. python基础教程第二版答案-《Python基础教程》(第2版修订版)中要注意的地方...
  3. 林子大了,什么鸟都有----.NET运用String的十八层境界
  4. pyecharts x轴字体大小调整_pyecharts 柱状图基础篇#学习笔记#
  5. 前端分页功能的实现以及原理
  6. 使用ZeroTier搭建大局域网利用VNC远程桌面
  7. python 最小二乘回归 高斯核_机器学习技法6-(支持向量回归)
  8. python 复制列表内容_Python复制列表列表
  9. 服务器磁盘会影响应用么,想了解服务器磁盘的IO吞吐量,用sqlio 工具会不会对当前服务器有影响...
  10. VS2017下载 vs2017社区版
  11. 微软enchange服务器安装,Exchange 2010 图文安装详解
  12. 沉没成本效应:每个人终其一生的断舍离
  13. 集美大学 - 2840 - 实验7-3 - 编程题
  14. linux中tac命令详解,一天一个shell命令 linux文本操作系列-tac,rev命令详解
  15. 多商户JAVA扫码点餐小程序源码SaaS模式
  16. 相机镜头光学中的一些疑难问题的解释
  17. html5研究背景及意义,基于HTML5的统计图表系统的研究与设计
  18. Ubuntu16.04安装搜狗中文输入法
  19. 微电子电路——期中总结
  20. Solidworks如何为装配体绘制剖面视图

热门文章

  1. 解决IDEA Maven项目无法下载依赖
  2. java查询比对是否重复_java-对象的ArrayList,比较对象并查找重复项,...
  3. ddr4服务器内存和普通内存_买主板送DDR4内存!微星日联合大促开幕
  4. ssm mysql增删改查_SSM配置并实现简单的数据库增删改查操作
  5. js获取当前时间戳,仿PHP函数模式
  6. es6 数组去重,数组里面的对象去重
  7. Django登录验证——原生表单验证
  8. foo bar的意思
  9. UIDatePicker的使用
  10. cocos2d-x 3.X (二)创建动起来的精灵