Linux【C编程】 信号以及信号的处理方式

文章目录

  • 1.什么是信号?
    • 1.1信号是内容受限的一种异步通信机制
    • 1.2信号由谁发出的?
    • 1.3信号由谁处理,如何处理
  • 2.常见的信号
  • 3.进程对信号的处理
    • 3.1用signal函数处理SIGINT信号
    • 3.2使用sigaction 函数
  • 4.alarm 和pause函数
    • 4.1 alarm函数详解
    • 4.2 pause函数详解

1.什么是信号?

1.1信号是内容受限的一种异步通信机制

在Linux中,信号是一种进程间通信(IPC)的机制。它用于通知某个进程发生了某种事件或异常。信号的本质是一种软件层次的模拟硬件中断的方法。当某个事件发生时,操作系统会向该事件的关联进程发送一个信号。进程接收到信号后,可以选择忽略该信号或者执行相应的操作来响应该信号。
可以总结为以下三点:
(1)信号的目的:用来通信
(2)信号是异步的(对比硬件中断)
(3)信号的本质上是int型数字编号(事先定义好的)

1.2信号由谁发出的?

信号可以由用户、系统或进程发送给目标进程。用户可以通过键盘输入、终端命令或系统调用等方式发送信号。系统则会在某些特定事件发生时自动发送信号,例如进程终止、硬件异常等。进程也可以通过系统调用或信号发送函数来发送信号给其他进程。在Linux中,可以使用kill命令或raise函数来向其他进程发送信号。某种软件条件满足后也会发出信号,如alarm闹钟时间到会产生SIGALARM信号,向一个读端已经关闭的管道write是会产生SIGPIPE信号。

1.3信号由谁处理,如何处理

  • 忽略信号:进程可以选择忽略收到的信号。这是大多数程序对信号的处理方式。但是,有些信号是不能被忽略的,例如SIGKILL和SIGSTOP,因为它们提供了使进程终止或停止的可靠方法。
  • 默认处理:如果进程没有为某个信号设置自定义的处理函数,那么系统会为该信号提供默认的处理方式。大多数信号的默认动作为终止进程。
  • 捕获信号:进程可以注册一个信号处理函数来指定如何响应某个信号。当进程接收到该信号时,会调用相应的处理函数来执行相应的操作。

2.常见的信号

1.SIGINT (2): 中断信号。通常由用户按下Ctrl + C发送,用于终止正在运行的程序。
2.SIGKILL (9): 杀死信号。这是一个无法被捕获或忽略的信号,强制终止进程。
3.SIGTERM (15): 终止信号。通常用于请求进程正常终止。与SIGKILL不同,进程可以捕获并且可以执行清理工作后再退出。
4.SIGSEGV (11): 段错误信号。当进程访问非法内存时触发,通常表示有bug导致了内存访问错误。
5.SIGILL (4): 非法指令信号。当进程试图执行非法的CPU指令时触发。
6.SIGHUP (1): 挂起信号。通常在与终端的连接断开时发送给进程,要求进程重新加载配置或重新初始化。
7.SIGUSR1 (10)和 SIGUSR2 (12): 用户自定义信号1和2。可以由用户自定义用途。
8.SIGALRM (14): 闹钟信号。通常由alarm()函数设置的定时器超时时发送给进程。

3.进程对信号的处理

3.1用signal函数处理SIGINT信号

当进程接收到SIGINT信号时,可以注册一个signal函数来执行后台保存操作等。
捕获Ctrl+C 终止信号 代码演示

#include <stdio.h>  
#include <stdlib.h>  
#include <signal.h>  
#include <unistd.h>  void handle_signal(int signal_number) {  printf("捕获到信号 %d\n", signal_number);  printf("我要退出了");exit(0);  // 退出程序  
}  int main() {  // 注册SIGINT信号的处理函数为handle_signal  signal(SIGINT, handle_signal);  while (1) {  printf("程序运行中... 正在等待信号\n");  sleep(1);  // 暂停1秒  }  return 0;  
}

signal函数是用于注册信号处理程序的标准函数之一。有一些优点和缺点:
优点:

  1. 简单易用:
    signal函数是C标准库提供的,使用起来相对简单,能够快速地注册信号处理函数。
  2. 基本功能完备:
    它提供了基本的信号处理功能,允许你指定在接收到特定信号时应该执行的处理函数。

缺点:无法简单地直接得知之前设置的对信号的处理方法。如果你使用 signal(SIGINT, new_handler) 来设置对 SIGINT 信号的新处理函数 new_handler,那么你不能直接获取或查询在调用 signal 函数之前对 SIGINT 信号所设置的处理函数。这种情况下,你无法在程序中简单地查询或检查当前 SIGINT 信号的处理函数是什么。这可能导致一定的不确定性,特别是在多个模块设置信号处理函数或者需要了解之前的处理方式时。

3.2使用sigaction 函数

sigaction 是用于设置信号处理函数的高级函数,相较于 signal 函数,它提供了更多的控制和选项。通过 sigaction 函数,可以更精确地管理信号处理。
sigaction 定义如下:

#include <signal.h>struct sigaction {void     (*sa_handler)(int);void     (*sa_sigaction)(int, siginfo_t *, void *);sigset_t   sa_mask;int        sa_flags;void     (*sa_restorer)(void);
};int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
  • signum是信号的编号
  • act是一个结构体 struct sigaction,包含新的信号处理函数,信号屏蔽集,以及标志位
  • oldact 是一个可选参数,用于存储之前的信号处理配置信息。

struct sigaction 结构体包含以下字段:

  • sa_handler:指定处理信号的函数,类似于 signal 函数中的处理函数。但与 signal 不同的是,sa_handler 允许设置为 SIG_DFL(默认操作)或 SIG_IGN(忽略信号)。
  • sa_sigaction:可选项,是带有更多信息的信号处理函数,用于处理信号和附加信息。如果设置了这个函数,sa_handler 就会被忽略。
  • sa_mask:用来设置在处理当前信号时需要屏蔽的信号集。
  • sa_flags:设置信号处理的一些标志位,例如 SA_RESTART 表示在某些系统调用中自动重启。
  • sa_restorer:一些特定系统用到的字段,一般无需设置。
    sigaction 函数的返回值为 0 表示成功,-1 表示失败。
    使用sigaction函数代码演示
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>void sigint_handler(int sig) {printf("捕获到 SIGINT 信号\n");printf("处理 SIGINT 信号...\n");exit(0);
}int main() {struct sigaction new_action, old_action;// 设置新的信号处理程序new_action.sa_handler = sigint_handler;sigemptyset(&new_action.sa_mask); // 清空信号屏蔽集new_action.sa_flags = 0;// 设置SIGINT信号的新处理程序if (sigaction(SIGINT, &new_action, &old_action) == -1) {perror("无法设置信号处理程序");return 1;}printf("按下 Ctrl+C 以发送 SIGINT 信号...\n");// 让程序保持运行,等待信号while (1) {sleep(1);}return 0;
}

在这里插入图片描述

4.alarm 和pause函数

4.1 alarm函数详解

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

seconds 参数表示定时器的秒数。当定时器到达设定的秒数后,会发送 SIGALRM 信号给当前进程。
注意:返回值有点绕,函数的返回值为前一个定时器剩余的秒数。如果之前有设置过定时器,则返回之前定时器剩余的时间,如果之前没有设置定时器,则返回 0。
代码演示:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#define DELAY  5
void alarm_handler(int signum) {printf("捕获到 SIGALRM 信号 bye\n");exit(0);
}int main() {signal(SIGALRM, alarm_handler); // 设置 SIGALRM 的处理函数unsigned int remaining_time = alarm(DELAY); // 设置定时器为5秒printf("alarm 返回值为 %u \n", remaining_time);   //这里的返回值其实为0 因为之前没有设置新的定时器只有一个的话,返回为0printf("等待%ds\n",DELAY);while(1) {// 程序的其他工作可以在这里执行sleep(DELAY);}return 0;
}

在这里插入图片描述
需要注意的是,alarm 函数设置的定时器是单次定时器,一旦定时器到时,就会被取消。如果需要重复定时功能,需要在 alarm_handler 函数中再次调用 alarm 来设置新的定时器。

4.2 pause函数详解

pause 函数是一个系统调用,用于使调用进程挂起直到收到一个信号。它通常用于程序中暂时等待某个信号的到来。

int pause(void);

pause 函数没有参数,调用它会使当前进程挂起,直到接收到一个信号为止。当进程接收到信号后,如果信号的默认处理方式是终止进程,那么进程将会终止。如果信号的默认处理方式是调用一个函数,那么进程会执行相应的信号处理函数,然后继续执行。通常,pause 函数用于让进程等待某个信号的到来,比如等待 SIGINT 或其他自定义信号。
代码演示:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
void sig_handler(int signum) {printf("捕获到自定义信号 %d\n", signum);if(signum==10){printf("执行退出命令\n");exit(0) ;}if(signum==12){printf("执行xxxx命令\n");}}int main() {signal(SIGUSR1, sig_handler); // 设置自定义信号的处理函数printf("等待自定义信号...\n");pause(); // 进程挂起等待自定义信号printf("自定义信号函数执行完毕,程序退出\n");return 0;
}

在终端编译运行之后,新开一个终端。可以用kill 发送自定义信号发送给进程。例如:

kill -s 12 5700

其中12 为自定义信号,Linux系统中一般10 或12 为自定义信号,5700为进程的pid。
可以使用ps -aux 查看进程pid
效果如下:
在这里插入图片描述

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

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

相关文章

vue element plus 安装

环境支持# Element Plus 可以在支持 ES2018 和 ResizeObserver 的浏览器上运行。 如果您确实需要支持旧版本的浏览器&#xff0c;请自行添加 Babel 和相应的 Polyfill 。 由于 Vue 3 不再支持 IE11&#xff0c;Element Plus 也不再支持 IE 浏览器。 Edge ≥ 79Firefox ≥ 78C…

用通俗易懂的方式讲解:大模型 RAG 在 LangChain 中的应用实战

Retrieval-Augmented Generation&#xff08;RAG&#xff09;是一种强大的技术&#xff0c;能够提高大型语言模型&#xff08;LLM&#xff09;的性能&#xff0c;使其能够从外部知识源中检索信息以生成更准确、具有上下文的回答。 本文将详细介绍 RAG 在 LangChain 中的应用&a…

愤怒的小红帽

欢迎来到程序小院 愤怒的小红帽 玩法&#xff1a;帮助小红帽安全送达老奶奶家&#xff0c;当狼进入靶子以后鼠标对准靶子&#xff0c; 点击鼠标左键&#x1f3f9;&#xff0c;对应的狼就会被射死&#xff0c;然后继续往前冲&#xff0c;快去&#x1f3f9;吧^^。开始游戏https:…

Jmeter压缩包安装

JMeter安装及配置-Mac 本章要点 前置条件命令行安装压缩包安装 在Mac上安装对应的JMeter工具有两种方式&#xff1a;一种直接借助终端命令行brew进行安装&#xff1b;另外一种和Window电脑一样去JMeter官网下载压缩包安装。 JMeter不需要安装&#xff0c;但是JMeter作为java应用…

伺服电机:伺服电机的控制方式(脉冲控制)

脉冲控制是伺服系统最常见的一种控制方式&#xff0c;基本上每家的伺服驱动器都支持脉冲模式。脉冲模式一般用于轴比较少的场合&#xff08;4轴及以下&#xff09;&#xff0c;轴数比较多的话就需要用总线来控制&#xff0c;毕竟伺服控制器的脉冲输入输出口的数量是有限的。 一…

Hive分区表实战 - 单分区字段

文章目录 一、实战概述二、实战步骤&#xff08;一&#xff09;创建图书数据库&#xff08;二&#xff09;创建国别分区的图书表&#xff08;三&#xff09;在本地创建数据文件&#xff08;四&#xff09;按分区加载数据1、加载中文书籍数据到countrycn分区2、加载英文书籍数据…

安全技能讲座 - 便携式灭火器 (Portable Fire Extinguishers )

【Transcript 】 火灾随时随地都可能发生&#xff0c;而且毫无征兆。如果您在家中或工作中遇到火灾&#xff0c;便携式灭火器可以帮助您保护自己&#xff0c;并有可能将火灾扼杀在摇篮中。本课程将向您介绍便携式灭火器、其工作原理和使用方法。成功完成本课程后&#xff0c;您…

字节跳动今年的校招薪资。。。

字节跳动校招情况分析 在写完了绝对顶流 华为 和近两年炙手可热的 比亚迪 的校招薪资之后&#xff0c;不少同学点名要看「字节跳动」。 确实&#xff0c;玩归玩&#xff0c;闹归闹&#xff0c;别拿字节开玩笑。 先来看看和公众号读者相关性较高的岗位校待遇&#xff1a; 研发算…

three.js实现电子围栏效果(纹理贴图)

three.js实现电子围栏效果&#xff08;纹理贴图&#xff09; 实现步骤 围栏的坐标坐标转换为几何体顶点&#xff0c;uv顶点坐标加载贴图&#xff0c;移动 图例 代码 <template><div class"app"><div ref"canvesRef" class"canvas-…

Linux的网络配置命令和网络设置实操

目录 一、网路命令 1.ifconfig 2.hostname 3.route 4.netstat 5.ss&#xff08;socket statistics&#xff09; 6.ping 7.nslookup 8.tcpdump 二、实操 1.单个网卡修改 2.双网卡配置 3.bond网卡绑定 一、网路命令 查看Linux基础的网络设置 网关route -nIP地址ifc…

算法与数据结构--最小生成树算法

一.应用的场景 类似于这种最小成本问题&#xff0c;实际上就是计算加权图把所有点连起来权重之和最小值的时候是怎么连接的。类似的问题还有最短耗时之类的问题。 二.最小生成树的定义 生成树&#xff1a; 图的生成树是它的一颗含有其所有顶点的无环连通子图。 【简单说就是所…

Java中的IO流

在Java中&#xff0c;I/O&#xff08;输入/输出&#xff09;流用于处理与输入和输出相关的操作。Java的I/O流按照数据处理的不同方式分为两大类&#xff1a;字节流和字符流。每个类别又分为输入流和输出流。以下是Java中常用的I/O流及其继承关系&#xff1a; 字节流&#xff0…

BERT Intro

继续NLP的学习&#xff0c;看完理论之后再看看实践&#xff0c;然后就可以上手去kaggle做那个入门的project了orz。 参考&#xff1a; 1810.04805.pdf (arxiv.org) BERT 论文逐段精读【论文精读】_哔哩哔哩_bilibili (强推!)2023李宏毅讲解大模型鼻祖BERT&#xff0c;一小时…

竞赛保研 基于深度学习的动物识别 - 卷积神经网络 机器视觉 图像识别

文章目录 0 前言1 背景2 算法原理2.1 动物识别方法概况2.2 常用的网络模型2.2.1 B-CNN2.2.2 SSD 3 SSD动物目标检测流程4 实现效果5 部分相关代码5.1 数据预处理5.2 构建卷积神经网络5.3 tensorflow计算图可视化5.4 网络模型训练5.5 对猫狗图像进行2分类 6 最后 0 前言 &#…

探索芊芊简历:一个革新的简历创建工具

在寻找理想工作的道路上&#xff0c;一份出色的简历是打开机遇之门的关键。今天&#xff0c;我想向大家介绍一款名为“芊芊简历”的免费简历编辑器&#xff0c;它以其独特的功能和先进的技术&#xff0c;为求职者提供了一个简单而高效的简历制作解决方案。 丰富多样的模板&…

虚拟局域网的基本概念与基本原理

虚拟局域网&#xff08;Virtual Local Area Network&#xff0c;VLAN&#xff09;是一种在物理局域网内部划分逻辑上独立的虚拟网络的方法。它通过在网络交换机上配置&#xff0c;将不同的设备分组到不同的虚拟网络中&#xff0c;实现了逻辑上分隔的网络通信。本文将介绍虚拟局…

北京大学漏洞报送证书

获取来源&#xff1a;edusrc&#xff08;教育漏洞报告平台&#xff09; url&#xff1a;教育漏洞报告平台(EDUSRC) 兑换价格&#xff1a;30金币 获取条件&#xff1a;北京大学任意中危或以上级别漏洞

【排序】快速排序

思想 快速排序是一种基于分治策略的排序算法&#xff0c;其核心思想通过选取一个基准元素&#xff0c;将数组分成两个子数组&#xff1a;一个包含小于基准元素的值&#xff0c;另一个包含大于基准元素的值。然后递归地对这两个子数组进行排序&#xff0c;最终将它们合并起来&a…

UltraScale 和 UltraScale+ 生成已加密文件和已经过身份验证的文件

注释 &#xff1a;如需了解更多信息&#xff0c;请参阅《使用加密和身份验证确保 UltraScale/UltraScale FPGA 比特流的安全》 (XAPP1267)。 要生成加密比特流&#xff0c;请在 Vivado IDE 中打开已实现的设计。在主工具栏中&#xff0c;依次选择“Flow” → “Bitstream Setti…

解决在eclipse2021中,用mysql-connector-java-8.0.18.jar不兼容,导致无法访问数据库问题

1.环境场景 组件版本mysql5.7.44mysql-connector-java80.18 2. 问题描述 报mysql-connector-java 驱动连不上mysql数据库。 3. 可能的原因分析 查看数据库连接句柄是否对 如果数据库连接句柄中没有 useSSLfalse 的话可能会导致这样的问题。 就像下面这样&#xff1a; jdb…