当前位置: 首页 > news >正文

Linux 信号产生方式

目录

信号的概念

信号的本质

名词解释

异步

前台进程

后台进程

前后台进程区别

中断

发送信号

前后台进程相关命令

信号产生的方式

查看有多少信号

进程怎么保存信号

方法1:键盘产生

signal 

过程

注意

方法2:使用系统调用发送信号

kill

raise

abort

方法3:通过异常

解释:除0为什么会终止进程

解释:空指针的解引用

小结

方法4:软件条件

alarm

小结


信号的概念

  • 目标进程发送通知消息的一种机制
  • 信号产生时,进程不一定立即处理它,而是在合适的时候处理,所以要能够保存信号
  • 信号是异步产生的
  • 进程通过不同的数字识别信号
  • 有64种情况(信号)让你中断程序

信号的本质

  • 用软件来模拟中断的行为
  • 信号的本质是一种进程间通信机制,用于通知进程发生了异步事件,并请求其对该事件进行处理
  • 信号本质上是一种软中断,允许操作系统以非阻塞的方式向进程发送通知,以便进程可以响应某些重要的系统或用户事件

名词解释

异步

  • 你做你的我做我的,不会立即影响我
  • 是任务之间的执行不需要彼此等待,而是可以独立地进行

前台进程

  • 系统层面上只能有一个,且必须有一个
  • 能接受用户输入
  • 运行前台进程时(shell除外),命令不能运行
  • 当没有前台进程时,OS会将shell提到前台
  • 可以理解为shell这个前台进程可以启动别的前台进程
  • 一定是正在运行的

后台进程

  • 方式:启动时 最后加一个&
  • 可以运行命令,因为这时shell变成前台进程
  • 可以运行命令是因为shell是前台进程

前后台进程区别

  • 能不能接收用户输入

中断

发送信号

  • 其实是写信号,操作系统写到对应task_struct的位图里

前后台进程相关命令

bg number

  • 后台暂停进程变成后台运行进程

fg number

  • 后台进程切到前台,启动

jobs

  • 查看后台任务

信号产生的方式

查看有多少信号

  • 向特定进程发送信号
  • 可以使用名字也可以使用数字
  • 没有0号信号,为了标识进程正常结束,不然不知道是否要读取退出码
  • 1-31:普通信号;;;34-64:实时信号
  • 实时信号:一般要求OS立即处理,一般不会出现信号丢失的情况(底层用队列,链表)
  • 每个进程都有一张自己的函数指针数组,数组的下标和信号编号强相关(底层指向的函数都是同一份)

进程怎么保存信号

进程是否收到信号---通过位图

  • 位置决定编号
  • 内容决定是否收到信号
  • 进程的PCB中维护这张位图
  • 用位图来管理的信号称为普通信号 

方法1:键盘产生

外设间接向CPU特定的针脚发送就绪信息的

  1. 数据层面上CPU不和外设打交道,但是在控制信息层面上打交道(通过CPU针脚)
  2. 硬件给CPU发送中断信息
  3. CPU和外设是间接连接的
  4. 90以上的设备要有中断
  5. 通过8259将外设信息转换为光电信号
  6. CPU中特定的针脚所对应的编号叫做中断号
  7. OS内部提供一个函数指针数组中断向量表,OS启动时候启动的第一张表),下标就是中断号对应硬件的读取方法,数据由外设拷贝到对应的内存区域里
  8. 按键盘的时候,键盘是基于中断来进行驱动的、
  9. 这个过程像信号,都有编号
  10. 输入的数据分两类:1.正常输入,2.控制数据

ctrl c

  • 一般情况下终止前台进程,但shell不会被终止
  • 本质就是给前台进程发送 2 号信号

ctrl z

  • 前台进程变成后台进程且暂停进程,这时候,shell会变成前台进程

ctrl \ :3号 默认终止进程

系统调用

signal 

  • 通过第一个参数找到地址,并将后面函数地址覆盖原来的函数(这也证明了确实每个进程都要一个函数指针数组,因为你要修改它啊)
  • 信号可以被handler自定义捕捉
  • 找到一张信号的函数指针表(PCB好像指向这个表),通过信号编号缩影到对应的函数

函数原型

#include <signal.h>typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);

参数

sigum

  • 表示要捕捉的信号编号

handler

  • 指向信号处理函数的指针,定义了在收到指定信号后应执行的处理方式
  • 实际上就是在 task_struct信号处理表(action 数组)中替换相应信号编号对应的处理函数指针

返回值

  • 成功时,返回信号的先前处理函数的指针
  • 失败时,返回 SIG_ERR 并设置 errno 以指出错误原因

实际作用就是替换掉原理的方法

#include <iostream>
#include <signal.h>
#include <unistd.h>void handler(int x)
{std::cout << x << "信号被写入" << std::endl;exit(0);
}
int main()
{signal(2, handler);while(true){std::cout << "正在运行" << std::endl;sleep(1);}
}

实验结果

  • 在按ctrl c 时会打印  2信号被写入
  • 说明ctrl c会触发2号信号
过程
  1. 键盘按下,通过硬件中断向CPU发送IRQ1信号,挂起正在处理的进程,先去处理键盘
  2. cpu将会执行中断号对应的中断向量表里的方法---到这处理器准备好了,数据下面这样来
  3. OS去读 键盘控制器 提供的 扫描码,给CPU处理,得到字符,放入输入缓冲区中(专门处理键盘的)
  4. OS读取输入缓冲中的数据,发现如果是组合键,OS会生成对应的信号
  5. OS将这个信号放入,前台进程的task_struct的pending对象中
  6. OS会定期将pending中的信号,给队友的进程
注意
  • 并不是所有的信号函数都可以被替换,9号就不行

man 7 signal

方法2:使用系统调用发送信号

kill

int kill(pid_t pid, int sig);

  • 可以向任何进程发送

系统调用原型

#include <sys/types.h>
#include <signal.h>int kill(pid_t pid, int sig);

参数

pid

  •  指的进程的pid

sig

  • 发送的信号类型

返回值

  • 成功返回0
  • 失败返回 -1, 设置errno

raise

  • 向调用它的进程发送一个信号

函数原型

#include <signal.h>int raise(int sig);

 sig

  • 发送的信号类型

返回值

  • 成功时:返回 0
  • 失败时:返回非零值

abort

  • 是一个用于立即终止程序执行的 C 标准库函数

函数原型

#include <stdlib.h>void abort(void);

特点 

  • 给自己发送信号SIGABRT,允许被捕捉(这个信号)
  • 就算这个信号被捕捉了,依旧可以终止进程
  • 因为用户捕捉了和我函数没关系,它不通过acitve数组里的下标去找,就是封装好的

方法3:通过异常

解释:除0为什么会终止进程

  1. CPU内部状态寄存器的溢出标志位中计算结果出现异常,即溢出标志位被设置为1(只占一个bit位)
  2. 因为OS要管理软件和硬件
  3. 硬件出问题了,OS向引发该错误的进程发送特定的信号,来终止这个进程
  4. 这个过程和语言没关系,所有语言都会,因为这是进程出现异常了
  5. 其实就是进程的上下文有问题,CPU不允许加载
  6. CPU报告给OS,OS去解决对应的进程

注意

  • CPU的寄存器属于CPU,但是寄存器里的内容不属于CPU,属于当前进程,即硬件上下文,所以状态标记寄存器的标志位为进程的上下文,所以只要将这个进程干掉,status标志位间接置0了(让其他进程覆盖)
  • 把进程杀掉就是处理异常的方式之一,也是恢复了CPU信息的健康状态方法之一 

将8号的处理方法改成一句打印,为什么会一直执行打印?

过程解释

  1. 进程运行,它的上下文加载到CPU内,状态标记寄存器表示错误
  2. 进程不继续执行 
  3. 通知OS,这个进程有问题,给他发送8号信号
  4. 执行8号信号对应的方法,打一句话
  5. 但是这个进程没有被退出,过段时间上下文又被加载到CPU上

解释:空指针的解引用

MMU

  • CPU内部有个MMU(集成的小的硬件电路)和页表一起找到物理内存地址,所以进来的是虚拟地址,出去的就是直接访问物理内存了

过程详解

  1. 页表中没有映射到0地址处
  2. MMU里面也有标志位,标志本次转化是否成功
  3. 一旦MMU出问题OS就知道了,又识别到硬件问题
  4. 所以OS将引起这个错误的进程干掉
  5. 本质是虚拟到物理转换出现的硬件问题 

小结

  1. 所以说vs中出现这些异常和vs没有关系,根本原因是被windows检查到了错误信息,进程被windows杀掉了,所以进程被杀,上下文就没了,错误信息就没了
  2. 语言的异常和系统的有区别,抛出异常的根本目的不是为了修正异常,而是为了在固定的地点打印出现的是什么异常,大部分异常是没法修正的;

  3. 抛出异常,处理异常的机制,更多是为了让执行流正常结束的

方法4:软件条件

概念

  • 当程序执行中达到某种特定状态或满足某种条件时,程序内部逻辑通过调用系统的信号接口来触发信号
  • alarm 函数本质上是一个软件定时器,它依赖的是程序自身的计时机制,而不是外部硬件
  • alarm 设置的倒计时结束后,程序会触发一个 SIGALRM 信号,通知程序某个时间点或条件达成;这种基于时间的触发机制也是一种软件条件

alarm

  • 函数是一个在 POSIX 标准中定义的系统调用,用于设置一个定时器,在指定的时间(秒)后触发 SIGALRM 信号(14)
  • 在一个进程中,alarm 计时器实际上只能设置一个;因此,一个进程内只有一个 alarm 计时器是有效的
  • 每次调用 alarm() 会返回上一次计时器的剩余时间(如果有的话),然后开始新的倒计时

函数原型

#include <unistd.h>unsigned int alarm(unsigned int seconds);

参数

seconds

  • 设置一个倒计时,若为0,则取消当前进程的计时器

返回值

  • 返回上一次调用 alarm() 的剩余秒数。如果没有设置过计时器或者上一个计时器已经完成,则返回 0

测试代码

#include <iostream>
#include <unistd.h>
#include <signal.h>int n = 0;
void handler(int sig)
{n = alarm(0);std::cout << n << std::endl;}
int main()
{signal(14, handler);std::cout<<getpid()<<std::endl;alarm(100);n = alarm(8);while(1){std::cout << n << std::endl;sleep(1);}std::cout<<getpid()<<std::endl;std::cout<<getpid()<<std::endl;std::cout<<getpid()<<std::endl;}

结果

  • 8个10,后序都是0

小结

http://www.dtcms.com/a/396464.html

相关文章:

  • O2O网站制作需要多少钱青岛建设网站的公司
  • 网站首页设计创意雄安做网站的公司
  • 网站建设 报告wordpress后台爆破
  • 12316网站建设方案西安市建设工程交易中心网站
  • 企业网站建设协议范本一个网站怎么留住用户
  • 科网站建设栖霞建设网站
  • 有什么可以做兼职的正规网站保护环境做网站素材
  • BrowseComp:为浏览智能体设计的简单而具挑战性的基准测试
  • 长沙网站优化页面wordpress中文名图片不显示
  • 域名购买后 怎么创建网站深圳南山做网站的公司
  • 网站制作找云主机做网站
  • 深圳做网站最好网站备案密码查询
  • 免费微场景制作网站用vs怎么做网站的导航
  • 老年夫妻做爰视频网站杭州企业宣传画册制作公司
  • 广州 网站制怎么重建wordpress
  • 让网站建设便宜到底全网推广营销
  • 开网站公司企业营销平台
  • 网站建设制作要学什么住房和城乡建设领域从业人员证书
  • 简洁大方网站建设wordpress 右拉
  • 哪个网站的旅游板块做的好桂林做手机网站
  • 哈尔滨市建设安全监察网站中宁网站建设
  • 做外贸接私单的网站网上接单做效果图哪个网站好
  • 临沂网站哪家好硬件开发学什么专业
  • 网站用户 微信商城relive模板wordpress分享
  • 电脑系统做的好的几个网站网站建设如何传视频
  • 【JavaEE】网络编程套接字
  • 网站优化基础tk域名
  • 怎么开网站企业网站推广排名
  • geo数据集合并 理解并准确解读PCA图中的批次效应对于数据分析至关重要
  • 沈阳网站建设费用公司网络组建方案