【Linux操作系统】信号的产生捕获

news2024/12/29 10:29:01

       🔥🔥 欢迎来到小林的博客!!
      🛰️博客主页:✈️林 子
      🛰️博客专栏:✈️ Linux
      🛰️社区 :✈️ 进步学堂
      🛰️欢迎关注:👍点赞🙌收藏✍️留言

目录

  • 信号是什么?
  • 信号是如何产生的?
    • 1.键盘输入
    • 2.程序(进程)异常
    • 3.系统调用
    • 4. 由软件条件来产生信号
  • 信号捕获
  • 总结:

信号是什么?

什么是信号? 信号是一种抽象概念,在我们的生活中就有各种各样的信号。 例如红绿灯,凌晨六点的鸡鸣声,你考试成绩不好时你爸妈的脸色。 这些都是信号。 而信号有一重要的特征就是,当这些信号出现时,你知道接下来会发生什么!然后采取相应的措施。

比如说:

红灯来了,你知道你不能过马路,所以你停止前进。

凌晨六点鸡叫了, 你知道已经天亮了,你可以起床,也可以继续睡觉,这都是处理信号的一种方式。

你考试成绩不好回家,你爸妈的脸色也可以告诉你,你爸妈现在心情很不开心,所以你知道你不能惹你爸妈生气。

以上都是现实中的信号,那么在我们的计算机程序中,也有信号!

而信号在产生之前,我们的程序就知道如何处理这个信号。

信号是如何产生的?

那么我们程序中的信号是如何产生的呢?

1.键盘输入

我们在键盘中有一些快捷键,比如 ctrl + c,会强制关掉当前前台运行的程序,本质是利用键盘输入,让OS向目标进程发送了2号信号。

我们可以写个死循环程序演示一下。

#include<iostream>


int main()
{
  while(1)
  {
    printf("hello linux\n");
  }
  return 0;
}

然后我们运行程序,按ctrl + c ,程序会被终止。实际上是产生了信号。

在这里插入图片描述

2.程序(进程)异常

当程序出现异常 , 例如 **空指针解引用,除0,等异常都会产生信号。 而本质是程序在执行中,发生了硬件错误。空指针解引用会发生内存错误, 除0会发生cpu计算错误。 所以就会产生信号,再由OS来处理这些信号。**这种情况就不演示了,因为这种异常在学习C语言的过程中想必大家都遇见过。

3.系统调用

我们可以用一些系统调用接口来产生信号,例如 我们命令行上的 kill 命令 。 本质就是系统调用int kill(pid_t pid, int signo) 函数来产生信号。还有 int raise(int signo) 函数来自己产生信号, 还有 void abort(void) 来产生 3号信号。

**int kill(pid_t pid, int signo) 演示 **

这个函数的第一个参数是一个进程的pid ,第二个参数是发送的参数,类似于我们 kill命令行。所以我们需要以命令行的方式 获取被发送信号进程的pid。

我们写一个kill 函数,参数用我们命令传进去的 argv[1] 和 argv[2]

#include<stdio.h>
#include<signal.h>
#include<stdlib.h>

int main(int argc , char* argv[])
{
  if(argc != 3)
  {
    printf("./mykill pid signal");
    return 1;
  }

  kill(atoi(argv[1]),atoi(argv[2]));
  return 0;
}

然后我们执行一个进程,每秒打印一次 hello linux。然后用 mykill 对 mypro 发送9号信号!

在这里插入图片描述

这样我们就模拟实现了一个 kill 命令。本质就算调用了系统调用接口 kill。

int raise(int signo) 演示

我们让程序打印5次 hello linux 后调用这个函数,并传参数9进去。看看进程会不会收到9号信号。

#include<stdio.h>
#include<unistd.h>
#include<signal.h>

int main()
{
  int count = 0;
  while(1)
  {
    printf("hello linux\n");
    sleep(1);
    count ++;
    if(count == 5)
    {
      raise(9);
    }
  }
  return 0;
}

然后我们运行这个程序

在这里插入图片描述

不难发现,五秒过后收到了9号信号,这就是自己产生信号的一种方式。

4. 由软件条件来产生信号

SIGPIPE是一种由软件条件产生的信号, 当我们在管道传输中,关闭了读端,而写端还在继续写入。那么就会产生SIGPIPE信号。

还有 alarm函数 产生 SIGALRM信号。

SIGPIPE信号暂且不演示,我们演示一下 alarm函数。

alarm函数是一个闹钟函数,参数传一个秒数,表示定时多少秒,时间到了之后则会收到alarm信号。返回值则是剩余的秒数,就是当闹钟被中断时。返回剩余的秒数,参数为0时则终端闹钟。

unsigned int alarm(unsigned int seconds)

我们先测试一下该函数。

#include<stdio.h>
#include<unistd.h>
#include<signal.h>

int main()
{
  alarm(5);
  while(1)
  {
    printf("hello linux1\n");
    printf("hello linux2\n");
  }
  return 0;
}

运行程序

在这里插入图片描述

我们发现五秒后收到信号。

那么我们取消闹钟试试

#include<stdio.h>
#include<unistd.h>
#include<signal.h>

int main()
{
  alarm(30); //注册闹钟
  int count = 0;
  while(1)
  {
    printf("hello linux1\n");
    printf("hello linux2\n");
    sleep(1);
    count++;
    if(count == 5)
    {
      int ret = alarm(0); //取消闹钟
      printf("ret = %d\n",ret); //打印剩余秒数
    }
  }
  return 0;
}

然后我们执行。

在这里插入图片描述

5s后闹钟取消了,返回了剩余的秒数,25秒。

信号捕获

信号的捕获函数:

#include <signal.h> //头文件

typedef void (*sighandler_t)(int); // 对函数指针typedef

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

signal函数的作用就是,如果接收到 signum , 那么就用handler函数去处理该信号。

举个例子:

我们执行下面代码,然后尝试用 kill命令对该进程发送2号信号。

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<stdlib.h>

//处理信号函数
void handler(int sign)
{
  printf("get a sign :  %d\n", sign);
  exit(0);
}

int main()
{
  signal(2,handler); //如果收到二号信号,那么用handler来处理
  while(1)
  {
    printf("hello world\n");
    sleep(1);
  }
  return 0;
}

然后我们测试一下。

在这里插入图片描述

我们发现最后输出了 get a sign 2 。 说明信号被捕捉了。

我们用 kill -l 可以查看系统中的信号。

在这里插入图片描述

我们只看前面31个,那么我们可以把前面31个都用 handler 处理。然后进行一个 除0 操作,会收到几号信号。

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<stdlib.h>

//处理信号函数
void handler(int sign)
{
  printf("get a sign :  %d\n", sign);
  exit(0);
}

int main()
{
  for(int i = 1;  i<= 31 ; i++)
    signal(i,handler); //如果收到二号信号,那么用handler来处理
 
  sleep(5) ; 
  int a = 5 / 0;  //5秒之后制造一个信号

  return 0;
}

然后我们运行一下。

在这里插入图片描述

5 秒过后,我们程序没有报错,相反是打印了 收到 8号信号的信息。而 8 号对应的就是SIGFPE信号,浮点数错误。在这里插入图片描述

现在知道信号可以捕获,那么问题来了, 9 号信号能否捕获呢? 我们可以用下面代码试一下。

我们写了一个死循环代码,然后用命令行发送9号信号,看看是否会被捕获。

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<stdlib.h>

//处理信号函数
void handler(int sign)
{
  printf("get a sign :  %d\n", sign);
  exit(0);
}

int main()
{
  for(int i = 1;  i<= 31 ; i++)
    signal(i,handler); //如果收到二号信号,那么用handler来处理
 
  while(1)
  {
    sleep(1);
    printf("hello world\n");
  }
  return 0;
}

我们试验一下。

在这里插入图片描述

最后我们发现, 9 号信号没有被捕获,进程还是被杀死了。

所以得出结论: 9号信号无法被捕获,操作系统不允许有金刚不坏的进程存在!

总结:

信号的四种产生方式:

1.终端键盘输入

2.进程异常

3.系统调用

4.软件条件产生

信号捕获函数:

sighandler_t signal(int signum, sighandler_t handler),其中 handler 是一个函数指针类型

特殊信号:

9号信号无法被捕获!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1017776.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

destoon关于archiver归档的性能优化

今天在处理一个项目时候发现archiver单个模块归档超过百万数据&#xff0c;打开速度就特慢&#xff0c;所以打开archiver下index.php文件进行分析&#xff0c;发现有句sql作怪&#xff0c;查询需要三四分钟&#xff0c;所以要修改这个。 $result $db->query("SELECT …

login (mobile email usercode)

手机、邮箱、用户编码登录 package login;/*** 常量类(改造拉到你自己项目里面)** author ZengWenFeng* date 2023.09.17* email 117791303qq.com* mobile 13805029595*/ public class Constant {// 登录界面的登录方式&#xff1a;手机、邮箱、用户名public static final Str…

YOLOv8学习

1 YOLOv8训练自己的数据集 1.1 部署和运行 1.1.1 第一步&#xff0c;下载代码 源码地址 1.1.2 第二步&#xff0c;创建环境 默认已经安装好conda conda create -n yolopy38 python3.8conda activate yolopy38安装所需要的包&#xff0c;先cd到代码目录下 pip install -r…

深眸科技自研工业AI视觉检测设备,检测精度99.9%加速智造进程

随着机器视觉技术的持续升级&#xff0c;国内制造行业不断发展&#xff0c;工艺水平持续优化&#xff0c;产品的数量和种类与日俱增。当前社会将产品质量标准提高&#xff0c;在满足正常的性能使用外&#xff0c;还需要具有良好的表面外观质量。但在工业制造过程中&#xff0c;…

【C语言】【数据存储】用%d打印char类型数据,猜结果是啥

题目代码如下&#xff1a; #include <stdio.h> int main() {char a -1;signed char b-1;unsigned char c-1;printf("a%d,b%d,c%d",a,b,c);return 0; }解题关键&#xff1a; 1.二进制存储&#xff1a;原码&#xff0c;反码&#xff0c;补码 互换 2.截断 3.整型…

密码学入门——Feistel网络

文章目录 参考书一、引入二、Feistel网络计算流程三、Feistel网络的解密四、Feistel网络的性质 参考书 图解密码技术&#xff0c;第三版 一、引入 DES的基本结构是由Horst Feistel设计的&#xff0c;因此也被成为Feistel网络&#xff08;Feistel结构&#xff0c;Feistel密码…

《动手学深度学习 Pytorch版》 6.6 卷积神经网络

import torch from torch import nn from d2l import torch as d2l6.6.1 LeNet LetNet-5 由两个部分组成&#xff1a; - 卷积编码器&#xff1a;由两个卷积核组成。 - 全连接层稠密块&#xff1a;由三个全连接层组成。模型结构如下流程图&#xff08;每个卷积块由一个卷积层、…

分布式电源接入对配电网影响分析(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

汽车电子——产品标准规范汇总和梳理(电磁兼容)

文章目录 前言 一、辐射发射 二、传导发射 三、沿电源线瞬态传导发射 四、辐射抗扰 五、大电流注入抗扰 六、磁场抗扰 七、便携式发射机抗扰 八、沿电源线瞬态抗扰 九、非电源线瞬态抗扰 十、电快速脉冲群抗扰 十一、静电抗扰 总结 前言 见《汽车电子——产品标准规…

Oracle数据库安装卸载

文章目录 一、数据库版本说明二、软件的下载和安装1.下载软件2.安装数据3.创建数据库4.PLSQL 三、数据库的卸载1.关闭相关服务3.卸载软件3.删除注册信息 四、用户和权限 一、数据库版本说明 1998年Oracle8i&#xff1a;i指internet&#xff0c;表示oracle向互联网发展&#xf…

bootstrap柵格

.col-xs- 超小屏幕 手机 (<768px) .col-sm- 小屏幕 平板 (≥768px) .col-md- 中等屏幕 桌面显示器 (≥992px) .col-lg- 大屏幕 大桌面显示器 (≥1200px) 分为12个格子 -后面的1代表占12分子1也就是一份 1.中等屏幕 <div class"container-fluid a">&l…

ARM Linux DIY(十二)NES 游戏

文章目录 前言交叉编译工具链使能 Cnes 游戏模拟器移植游戏手柄调试 前言 很多小伙伴为了不让自己的 V3s 吃灰&#xff0c;进而将其打造成游戏机。 我们 DIY 的板子具备屏幕、扬声器、USB Host&#xff08;可以接游戏手柄&#xff09;&#xff0c;当然也要凑一凑热闹。 交叉编…

SpringBootTest

SpringBootTest注解 --基于SpringBoot2.5.7版本 可以在运行基于Spring Boot的测试的测试类上指定的注释。在常规的Spring TestContext框架之上提供了以下特性: 默认提供SpringBootContextLoader作为ContextLoader&#xff0c;也通过 ContextConfiguration(loader…)来自定义 若…

docker安装zookeeper(单机版)

第一步&#xff1a;拉取镜像 docker pull zookeeper第二步&#xff1a;启动zookeeper docker run -d -e TZ"Asia/Shanghai" -p 2181:2181 -v /home/sunyuhua/docker/zookeeper:/data --name zookeeper --restart always zookeeper

基于改进莱维飞行和混沌映射的粒子群优化BP神经网络预测股票价格研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

1990-2022年上市公司常用控制变量数据(1300+变量)

1990-2022年上市公司常用控制变量数据&#xff08;1300变量&#xff09; 1、时间&#xff1a;1990-2022年 2、指标&#xff1a;共计1391个变量&#xff0c;包括但不限于以下类别&#xff1a;、基本信息&#xff08;性质、行业、地址&#xff09;、股票市场&#xff08;发行、…

阿里云无影云电脑详细介绍_无影优势价格和使用

什么是阿里云无影云电脑&#xff1f;无影云电脑&#xff08;原云桌面&#xff09;是一种快速构建、高效管理桌面办公环境&#xff0c;无影云电脑可用于远程办公、多分支机构、安全OA、短期使用、专业制图等使用场景&#xff0c;阿里云百科分享无影云桌面的详细介绍、租用价格、…

通过指针变量存取一维数组元素

任务描述 本关任务&#xff1a;编写程序用指针变量遍历一个数组。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a; 1.指向数组元素的指针的运算 2.如何遍历数组。 视频1 指针与一维数组 指向数组元素的指针的运算 指针与整数的加减运算 有数组和指针变量的…

区块链(3):区块链去中心化

1 点对点同步区块链的流程 流程图如下&#xff1a; 流程讲解&#xff1a; &#xff08;1&#xff09;连接节点 &#xff08;2&#xff09;向该节点请求最新区块 &#xff08;3&#xff09;请求到区块以后&#xff0c;根据返回的最新区块前置hash是否和我本身的区块hash相等…

抖音矩阵系统-60+自媒体平台一键发布-短视频获客系统

当老板做企业的&#xff0c;想在抖音上做生意的&#xff0c;一定一定要开通蓝V企业号线索版来做矩阵。看看我每天的线索都是999&#xff0c;客服都接待不过来&#xff0c;现在还有300个客资未分配&#xff0c;抖音都在推了企业员工号的玩法&#xff0c;你还在质疑什么&#xff…