Linux进程信号

Linux信号

    • 信号概述
      • 信号的记录与发送
  • 信号的产生
    • signal函数(自定义行为)
    • 产生信号
      • Core Dump
        • 程序异常产生信号
      • status(16位)
    • ctrl+z信号
    • 系统调用产生信号
      • kill
      • raise
      • abort
    • 软件条件产生的信号
      • alarm
  • 信号的保存
    • 修改位图
      • ①sigprocmask
      • ②sigpending
  • 信号的处理
    • sigaction
      • volatile关键字

信号概述

像上课铃声这种信号,我们识别接收后,知道该上课了,这是我们后天学习养成的默认意识

在进程收到信号后,它是知道该怎么做的 ,程序员内置了默认的处理行为

进程的运行跟信号的产生属于异步关系:
1.进程不一定立刻去处理已经到来的信号
2.如果进程在处理优先级更高的事情,可以暂时不处理信号,等到合适的时候再处理。
3.会用某种方式记录下已经到来的但没处理的信号,以便在空闲的时候处理这些信号

异步:二者之间互不影响
同步:二者之间相互影响

处理信号的三种方式:
1.默认行为

2.提供信号处理函数,要求内核在处理该信号时切换到用户态来执行这个处理函数,称为捕捉信号

3.忽略

kill -l 查看信号
Linux进程信号_第1张图片
总共有62个信号(1-31普通信号,34-64实时信号)
Linux进程信号_第2张图片

信号的记录与发送

信号是在进程的task_struct中记录的,通过位图来记录是否产生信号

所以进程收到信号,本质是操作系统修改了进程中的信号位图(只能是OS)

操作系统是软硬件资源的管理者

信号的产生

signal函数(自定义行为)

Linux进程信号_第3张图片
示例:
ctrl c(2号信号) Linux进程信号_第4张图片Linux进程信号_第5张图片
通过键盘输入ctrl+c(2号信号)来给进程发送信号

ctrl c(键盘产生的信号)只能发送给前台进程,一个命令后面加个&可以放到后台运行,这样Shell不必等待进程结束就可以接受新的命令,启动新的进程。
可以用kill发送信号给后台进程
并不是所有的信号都能捕捉,比如9号就不能(全部捕捉就意味着可能不能杀死进程)

产生信号

Core Dump

SIGINT(Term)的默认处理动作是终止进程
SIGQUIT(Core)的默认处理动作是终止进程并且Core Dump

在这里插入图片描述
用3号信号关掉进程的时候,会进行核心转储

查看系统当中的系统资源:ulimit - a
Linux进程信号_第6张图片
云服务器下的核心转储是默认关闭的(why:每次运行程序挂掉都会在磁盘产生不小的core.pid文件)

我们把它打开:
Linux进程信号_第7张图片
再次运行程序向进程发出三号信号(Ctrl+\)
在这里插入图片描述
多产生一个core文件,5865是发生核心转储的进程ID
在这里插入图片描述

核心转储:
代码运行中出错时,将进程内存中的核心数据转储到磁盘上,生成core.pid文件
目的是为了调试定位问题

程序异常产生信号

利用core文件进行事后调试除0异常
Linux进程信号_第8张图片
Linux进程信号_第9张图片使用命令core-file core.pid 查看错误信息在这里插入图片描述
可以看到被8号信号(SIGFPE)终止,15行报错
Linux进程信号_第10张图片
进程为什么会崩溃
程序崩溃的本质是收到了OS发送的信号

进程为什么会收到信号
当程序发生某种错误时,一定会在硬件层面上有所表现,进而被OS识别,向该进程发出信号

status(16位)

Linux进程信号_第11张图片

子进程正常退出:
Linux进程信号_第12张图片
在这里插入图片描述
子进程异常退出:
Linux进程信号_第13张图片

在这里插入图片描述
子进程收到8号信号,并且coredump为1,说明运行时程序崩溃时core dump了

ctrl+z信号

ctrl+z(20号信号)暂停进程,把进程放到后台

jobs:查看后台进程
fg 序号 将后台恢复到前台

Linux进程信号_第14张图片

系统调用产生信号

kill

Linux进程信号_第15张图片
模拟实现kill函数(利用命令行参数)

命令行参数:
Linux进程信号_第16张图片
将字符串转为int在这里插入图片描述
Linux进程信号_第17张图片
Linux进程信号_第18张图片
Linux进程信号_第19张图片
可以看到通过命令行参数,在程序里面进行系统调用kill,依然产生了信号

raise

在这里插入图片描述
作用:自己给自己发信号

示例:
Linux进程信号_第20张图片
Linux进程信号_第21张图片

abort

在这里插入图片描述

abort函数使当前进程接收到信号而异常终止
特性:就像exit函数一样,abort函数总是会成功的,所以没有返回值

示例:
Linux进程信号_第22张图片

Linux进程信号_第23张图片

软件条件产生的信号

SIGPIPE是一种由软件条件产生的信号

alarm

在这里插入图片描述
在传入时间后,向进程发送14号信号
Linux进程信号_第24张图片
不像abort,捕获后并没有终止进程
在这里插入图片描述
每隔一秒打印递增的count:
每次alarm发出信号捕获后,有设置新的闹钟,就会一直打印
Linux进程信号_第25张图片
Linux进程信号_第26张图片

信号的保存

1.实际执行信号的处理动作称为信号递达
2.信号从产生到递达之间的状态,称为信号未决
3.进程可以选择阻塞某个信号
4.被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作

收到信号后:Linux进程信号_第27张图片
所以在阻塞时(1到31号信号)收到多次该信号只处理一次

修改位图

sigset_t(信号集)
作用:用于描述进程的block位图,pending位图的信号集

#include
int sigemptyset(sigset_t *set);//清空
int sigfillset(sigset_t *set);// 全部置1
int sigaddset (sigset_t *set, int signo);//添加信号到信号集
int sigdelset(sigset_t *set, int signo);//删除信号到信号集
int sigismember(const sigset_t *set, int signo);//判断信号是否存在

Linux进程信号_第28张图片

系统调用让设置能够修改PCB里面的内容:

①sigprocmask

sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)

int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
返回值:若成功则为0,若出错则为-1

how:如何修改当前信号集

SIG_BLOCK 添加set中的包含的信号到信号集
SIG_UNBLOCK 解除信号集中set所包含的信号
SIG_SETMASK 将set拷贝给当期阻塞信号集

set:用set信号集来修改当前阻塞信号集
oset:阻塞信号集会先备份到oset里面,是输出型参数,方便恢复信号集

②sigpending

在这里插入图片描述
获取当前进程的未决信号集,通过set参数传出(输出型参数)。调用成功则返回0,出错则返回-1

示例:

Linux进程信号_第29张图片
在这里插入图片描述
可以看出:先屏蔽了2号信号,想进程发送2号信号不会被递达,pending对应位置修改为1

示例二:
Linux进程信号_第30张图片

Linux进程信号_第31张图片
先阻塞了2号信号,发送二号信号,pending修改,count==6时恢复了2号信号,2号信号递达,执行捕捉代码,最后信号执行完,对应pending修改为0

信号的处理

上面提到进程收到信号之后,不是立即处理信号,而是在合适的时候
这个合适的时候就是内核态切换回用户态的时候

内核态通常执行OS代码,权限优先级非常高
用户态执行普通用户的代码的状态,受OS的管理

Linux进程信号_第32张图片
Linux进程信号_第33张图片

自定义处理函数状态切换4次
默认,忽略只切换了两次

sigaction

int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
作用:自定义捕捉信号
类似于sigprocmask

struct sigaction:
Linux进程信号_第34张图片
sa_sigaction:处理实时信号的接口
sa_handler:捕捉执行的方法(如果设置成SIG_DFL表示执行系统默认动作)
sa_flags:通常设置为0
sa_mask:说明需要额外屏蔽的信号

当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字(自动添加到mask中),当信号处理函数返回时自动恢复原来的信号屏蔽字

示例:

Linux进程信号_第35张图片
Linux进程信号_第36张图片

volatile关键字

让以下代码在优化级别-O3 下运行
Linux进程信号_第37张图片

在这里插入图片描述
加上volatile后
Linux进程信号_第38张图片
在这里插入图片描述
就会捕获信号退出循环
Linux进程信号_第39张图片
加入volatile后,不会将flag先置入寄存器,而是在读取内存中的值到寄存器中再检测

volatile的作用:保证了内存可见性

你可能感兴趣的:(笔记,Linux,linux,运维,服务器)