百金买骏马,千金买美人,万金买爵禄,何处买青春?

目录

信号的概念

信号的种类:

kill -l 命令可以查看信号列表

man 7 signal 查看信号详细内容

信号的产生

补充知识 Core Dump(转储内存)

补充知识:与信号相关的数据结构

对于不可靠信号

接收信号

信号的处理:

阻塞信号集:

未决信号集:

信号的捕获:

这里为了帮助理解,展了一段存在bug的代码:

运行结果:​

结语

参考的文章

参考的书籍


信号的概念

在计算机科学中,信号是Unix、类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式。它是一种异步的通知机制,用来提醒进程一个事件已经发生。当一个信号发送给一个进程,操作系统中断了进程正常的控制流程,此时,任何非原子操作都将被中断。如果进程定义了信号的处理函数,那么它将被执行,否则就执行默认的处理函数。(摘自百度百科)

特别强调对 异步中断 理解:因为信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。

信号的种类:

kill -l 命令可以查看信号列表

man 7 signal 查看信号详细内容

  • 每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定 义 #define SIGINT 2
  • Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,因此,把那些建立在早期机制上的信号叫做"不可靠信号",信号值小于SIGRTMIN(在我的机器里SIGRTMIN=34,SIGRTMAX=64)的信号都是不可靠信号。这就是"不可靠信号"的来源。
  • 关于可靠信号和不可靠信号

信号的产生

  • 按键产生,如:Ctrl+c、Ctrl+z、Ctrl+\
  • 系统调用产生,如:kill()、raise()、abort()
  • 软件条件产生,如:定时器alarm()、pause()
  • 硬件异常产生,如:非法访问内存(段错误)、除0(浮点数例外)、内存对齐出错(总线错误)
  • 命令产生,如:kill命令

上面的一些函数或命令都对百度百科进行了超链接,如果还有疑问,可以参考 《unix 环境高级编程[第10章]》

补充知识 Core Dump(转储内存)

  • wait()和waitpid(),都有一个status参数,该参数是一个输出型参数,由操作系统填充。
  • 如果传递NULL,表示不关心子进程的退出状态信息。
  • 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。 status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图:

  • 关于wait()和waitpid()所返回相关的宏
  • linux中core dump开启使用教程

我们可以通过位运算,也可以通过宏来得到我们需要的信息,具体代码如下

#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>int main(void)
{pid_t pid;if ((pid = fork()) == -1)perror("fork"), exit(1);if (pid == 0)  //child{sleep(4);int a=13/0; //故意写错,让程序异常退出exit(0xFF);}else{int st;int ret = wait(&st);// if(ret > 0 &&WIFEXITED(st) )  WIFEXITED(st)进程正常退出为真,和下面等价if (ret > 0 && (st & 0X7F) == 0){ // 正常退出printf("正常退出\n");printf("宏:st:%p child exit code:%d sig code : %d     \n",st,WEXITSTATUS(st),WTERMSIG(st));printf("移位运算:st:%p child exit code:%d sig code : %d\n",st,(st >> 8) & 0XFF,st & 0X7F);printf("core文件是否产生:%d,core dump 标志是:%d\n",WCOREDUMP(st),st & 0X80);}else if (ret > 0){ // 异常退出printf("异常常退出\n");printf("宏:st:%p child exit code:%d sig code : %d     \n",st,WEXITSTATUS(st),WTERMSIG(st));printf("移位运算:st:%p child exit code:%d sig code : %d\n",st,(st >> 8) & 0XFF,st & 0X7F);printf("core文件是否产生:%d,core dump 标志是:%d\n",WCOREDUMP(st),st & 0X80);//core会输出128,因为它刚好在第8位 ,即0X80}}
}

运行结果:

补充知识:与信号相关的数据结构

具体一点是这样子(图片来源)

然后我们再画简单点

对于不可靠信号

  • 每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。在上图的例子中,SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。
  • SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
  • SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。 如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。

接收信号

信号的处理:

  1. 执行默认动作
  2. 忽略(丢弃)
  3. 捕捉(调用户处理函数)

阻塞信号集:

  • 将某些信号加入集合,对他们设置屏蔽,当屏蔽x信号后,再收到该信号,该信号的处理将推后(解除屏蔽后)。

未决信号集:

  1. 信号产生,未决信号集中描述该信号的位立刻翻转为1,表信号处于未决状态。当信号被处理对应位翻转回为0。这一时刻往往非常短暂。
  2. 信号产生后由于某些原因(主要是阻塞)不能抵达。这类信号的集合称之为未决信号集。在屏蔽解除前,信号一直处于未决状态。

介绍了这么多知识,现在我们来对信号再进行一个捕获

信号的捕获:

  • 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。由于信号处理函数的代码 是在用户空间的,处理过程比较复杂,举例如下: 用户程序注册了SIGQUIT信号的处理函数sighandler。当前正在执行 main函数,这时发生中断或异常切换到内核态。 在中断处理完毕后要返回用户态的main函数之前检查到有信号 SIGQUIT递达。 内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函 数,sighandler 和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是 两个独立的控制流程。 sighandler函数返 回后自动执行特殊的系统调用sigreturn再次进入内核态。 如果没有新的信号要递达,这次再返回用户态就是恢复 main函数的上下文继续执行了。

这里为了帮助理解,展了一段存在bug的代码:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>void handler1(int sig){int olderrno=errno;pid_t child=waitpid(-1,NULL,0);if(child<0)fprintf(stderr,"    waitpid error");printf("    Handler reaped child %d\n",(int)child);sleep(1);printf("%s\n",strerror(olderrno));
}int main(){/*第一个参数 是信号名       SIGHLD 在一个进程终止或者停止时,将SIGCHLD信号发送给其父进程,按系统默认将忽略此信号,如果父进程希望被告知其子系统的这种状态,则应捕捉此信号。第二参数是信号处理函数  其中 常量SIG_IGN代表忽略 SIG_DFL代表 按系统默认动作 */  //返回值 若成功,返回以前的信号处理配置; 若出错,返回 SIG_ERRif(signal(SIGCHLD,handler1)==SIG_ERR)   //对信号进行捕获fprintf(stderr,"signal error");//创建子进程int i=0;for(i=0;i<3;i++){if(fork()==0){ //childprintf("Hello i am child %d\n",(int)getpid());exit(0);}}//父进程运行printf("Hi i am parent %d\n",(int)getpid());while(1);exit(0);
}

运行结果:

这里我们注意到尽管发送了3个SIGCHLD信号给父进程,但其中只有两个信号被成功接收了,因此父进程只回收了两个子进程.而子进程31288则成为了一个僵尸进程.

那么是哪里出错了呢?这段代码来源《深入理解计算机系统(第8章 图8-36)》

结语

本文也仅仅是对信号的一个浅谈,意在先树立一个大的框架,希望对读者能有所帮助,作者本人也在一路学习的过程中,很多细节由于自身经验和时间的原因,并没办法给读者细细道来,但是本文所参考的文章和书籍均会在文末放上链接,当然我也很欢迎读者如果有问题可以私信于我或在底下评论,我也会很乐意分享我的见解.

这些是我们没有细细讨论的内容,其实每一个函数都很有意思,这边再次推荐一下这本好书《UNIX环境高级编程》,当然还有《深入理解计算机系统》

参考的文章

Linux应用与网络编程 - 随笔分类(第2页) - 浅墨浓香

Linux - 信号 | C++ 全栈知识体系

可靠信号与不可靠信号 - wsw_seu - 博客园

linux 信号处理 六(全) - 走看看

参考的书籍

《深入理解计算机系统》

《UNIX环境高级编程》

=============分界线===============

关于core文件的再补充(2022/01/12)

用prctl()函数控制不生成core文件

[Linux学习笔记] 浅谈信号(文章含不少学习资源)相关推荐

  1. 学习笔记--浅谈LoRa与LoRaWAN

    浅谈LoRa与LoRaWAN 1.什么是LoRa LoRa是semtech公司创建的低功耗局域网无线标准,低功耗一般很难覆盖远距离,远距离一般功耗高,要想马儿不吃草还要跑得远,好像难以办到. LoRa ...

  2. [软件工程学习笔记]浅谈敏捷开发

    在移动电子设备如此普及的今天,看着琳琅满目的手机APP市场,你不知道下一秒什么会突然变得炙手可热,什么会瞬间销声匿迹.顺应时代的潮流,软件开发也从重型过程向轻量型敏捷发展.作为软件的开发者,这些都是值 ...

  3. 学习笔记-----浅谈汇编指令CMP运行机制

    在汇编中,CMP和JMP指令常常用于比较操作,而且查看反汇编源码时也发现不管是.IF伪指令还是其他的底层都是用CMP实现的. 指令格式: CMP 目的操作数,源操作数 计算机在遇到CMP指令的时候,C ...

  4. python中文字符串编码_浅谈python下含中文字符串正则表达式的编码问题

    前言 Python文件默认的编码格式是ascii ,无法识别汉字,因为ascii码中没有中文. 所以py文件中要写中文字符时,一般在开头加 # -*- coding: utf-8 -*- 或者 #co ...

  5. vue学习笔记-03-浅谈组件-概念,入门,如何用props给组件传值?

    vue学习笔记-03-浅谈组件-概念,入门,如何用props给组件传值? 文章目录 vue学习笔记-03-浅谈组件-概念,入门,如何用props给组件传值? 什么是组件? 为什么要使用组件? 如何使用 ...

  6. 转:浅谈程序员的英语学习

    转自:http://www.cnblogs.com/haoyifei/p/5687235.html 浅谈程序员的英语学习 作为在中国工作的程序员,不懂得英语似乎也不妨碍找到好工作,升职加薪.但程序员这 ...

  7. 浅谈元认知理论与学会学习

    摘自:http://blog.sina.com.cn/s/blog_50f98dfa0100a86r.html 浅谈元认知理论与学会学习                                 ...

  8. 浅谈程序员的英语学习

    作为在中国工作的程序员,不懂得英语似乎也不妨碍找到好工作,升职加薪.但程序员这个工种则稍有不同,因为程序,尤其是高级语言,基本上都是由英语 和数字表达式构成的.英语对于程序员十分重要.我的大学本科全部 ...

  9. 学了计算机专业英语感悟,浅谈计算机专业英语的学习

    浅谈计算机专业英语的学习 江苏盐城技师学院 李书琴 [摘 要]职业教育是现代化教育的重要组成部分,其目标在于培养大批有理想.有道德.有文化.有纪律,具有一定知识与技 能的劳动者和各种实用人才.英语作为 ...

最新文章

  1. 老板要我开发一个简单的工作流引擎
  2. 一个技术人的知识管理方法论
  3. 使用Vue构建中(大)型应用
  4. 算法题解题方法技巧及典例汇总
  5. 查询和追踪快递单的流向有这么难吗?用VFP其实太简单
  6. Deepin安装Windows字体(如微软雅黑)
  7. 新手入门吉他买什么好?十年吉他老司机教你如何远离烧火棍,附上靠谱吉他品牌推荐!
  8. IVL和SVL的区别
  9. 程序员不能只会敲代码还要会投资理财
  10. 《三体》里的超级计算机_我们今天能造出来吗?
  11. 所谓的日常 #8 - 王司徒巧使連環計 董太師大鬧鳳儀亭
  12. 苏州各园林的地址和票价
  13. 数据科学家:探索世界的探险家与怀疑一切的大侦探?
  14. python无法print彩色字体
  15. iOS架构设计(一)- MVC
  16. 利用VBA编程制作互动效果的PPT
  17. 慧都MES系统助力制造型工厂实现透明化、精细化管理
  18. halcon中相似变换、仿射变换、投影变换的区别以及应用方式和例程
  19. 【Cocos Creator】 摄像机移动碰到的一些问题
  20. 怎么把jpeg改成pdf格式

热门文章

  1. CentOS6 64bit系统一键快速安装VNC桌面实现Linux桌面
  2. Trinity安装全过程并解决部分报错
  3. C语言只能在开头定义变量?
  4. matlab中洛伦兹拟合,基于MATLAB洛伦兹线型非线性拟合算法实现
  5. PhotoShop彩色图片打印机只有四中颜色操作步骤:
  6. 三相异步电机,直流电机工作原理
  7. jenkins配置Pipeline项目报错
  8. lammps教程:delete_atoms删除原子后原子ID不连续的两种解决方案
  9. Linux的基础指令
  10. 椭圆一般方程求解椭圆标准方程参数