深入了解Linux信号:作用、产生、捕捉和阻塞

这里写目录标题

  • 引言
  • 1. 信号的基本概念
    • 1.1 信号的分类和编号:
    • 1.2 查看信号默认处理动作
    • 1.3 信号的作用
    • 1.4 信号的产生
  • 2. 常见信号及其作用
        • 示例
  • 3. 信号捕捉和处理
      • 3.1 信号捕捉函数
      • 3.2 sigaction 函数
        • 示例
  • 4. 信号阻塞
    • 示例
  • 结语

引言

Linux操作系统中,信号是一种重要的进程间通信机制,用于通知进程发生了某些事件。信号既可以是来自内核的通知,也可以是由其他进程发送的。在本篇博客中,我们将深入探讨Linux信号的作用、产生机制、捕捉方式以及信号阻塞的概念。

1. 信号的基本概念

1.1 信号的分类和编号:

Linux中的信号被分类为标准信号实时信号

标准信号是最基本的信号类型,由整数编号表示,编号范围是1到31。
实时信号是Linux中的扩展信号类型,由整数编号表示,编号范围是32到64。

在这里插入图片描述

为什么31-34中间缺少两个信号无法展示呢?

kill -l 命令用于列出系统支持的所有信号名称,但它并不显示编号为32和33的信号。这是因为Linux中的信号被分类为标准信号和实时信号,而编号为32和33的信号属于实时信号,它们在kill -l的输出中不会显示。

1.2 查看信号默认处理动作

man 7 signal

在这里插入图片描述

1.3 信号的作用

信号在Linux系统中有多种作用,包括通知进程某个事件的发生、中断进程的正常执行、以及在进程间传递简单的消息等。不同的信号有不同的含义和影响,了解这些信号是理解Linux系统行为的关键(常见信号及作用请看第2点)。

1.4 信号的产生

信号可以由多种来源产生,包括硬件故障、用户输入、操作系统事件等。例如,Ctrl+C组合键产生SIGINT信号,表示中断信号,通常用于终止正在运行的程序。此外,操作系统还可以向进程发送信号以通知发生的事件,如进程终止、停止等。

2. 常见信号及其作用

SIGINT (2) - 中断信号:

  • 作用:用于通知进程中断正在执行的操作,通常由用户通过键入 Ctrl+C 生成。

  • 例子:在终端中运行一个长时间执行的程序,用户可以按下 Ctrl+C 来发送 SIGINT 信号,终止程序的执行。
    在这里插入图片描述
    SIGTERM (15) - 终止信号:

  • 作用:请求进程正常终止,允许进程清理资源和保存状态。

  • 例子:当系统关闭时,操作系统向所有运行的进程发送 SIGTERM 信号,请求它们正常退出。
    在这里插入图片描述
    SIGKILL (9) - 强制终止信号:

  • 作用:立即终止进程,不允许进程清理资源或保存状态。

  • 例子:在系统管理员需要立即停止一个无响应的进程时,可以使用 kill -9 命令发送SIGKILL信号。
    在这里插入图片描述

SIGSEGV (11) - 段错误信号:

  • 作用:表示进程尝试访问其无法访问的内存区域,通常是由于指针错误或内存越界引起。
  • 例子:如果一个程序尝试访问已经释放的内存块,操作系统将发送SIGSEGV信号给该进程,使其崩溃。
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>// SIGSEGV信号处理函数
void segv_handler(int signum) {printf("Segmentation fault (SIGSEGV) caught. Exiting...\n");exit(EXIT_FAILURE);
}int main() {// 设置SIGSEGV信号处理函数signal(SIGSEGV, segv_handler);int *ptr = NULL;// 尝试解引用空指针,导致段错误*ptr = 10;// 这里的代码不会执行,因为上面的语句导致了段错误printf("This line will not be reached.\n");return 0;
}

我们通过signal函数将segv_handler函数与SIGSEGV信号关联起来。当运行程序并尝试解引用空指针时,会触发段错误,然后程序会捕获SIGSEGV信号并执行segv_handler函数。在这个处理函数中,我们输出一条消息并调用exit退出程序。

SIGUSR1 (10) 和 SIGUSR2 (12) - 用户定义信号:

  • 作用:这两个信号没有预定义的含义,可以由用户自定义其作用。
  • 例子:某个应用程序可以使用这两个信号来触发自定义的操作,比如重新加载配置文件或执行特定的功能。
示例
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>// SIGUSR1信号处理函数
void sigusr1_handler(int signum) {printf("Received SIGUSR1 signal.\n");// 在这里执行与SIGUSR1相关的操作
}
// SIGUSR2信号处理函数
void sigusr2_handler(int signum) {printf("Received SIGUSR2 signal.\n");// 在这里执行与SIGUSR2相关的操作
}int main() {// 设置SIGUSR1和SIGUSR2信号处理函数signal(SIGUSR1, sigusr1_handler);signal(SIGUSR2, sigusr2_handler);printf("My process ID: %d\n", getpid());printf("I am process[%d], Waiting for SIGUSR1 or SIGUSR2 signals...\n",getpid());while (1) {// 进程持续运行sleep(1);}return 0;
}

在这里插入图片描述

这些信号的作用覆盖了从正常终止到异常情况的多个场景,使得进程能够及时响应各种事件。在编写程序时,了解这些信号及其作用是确保程序稳定性和可维护性的关键。

3. 信号捕捉和处理

Linux允许进程捕捉和处理信号,以执行自定义的操作。信号处理可以通过以下方式实现:

3.1 信号捕捉函数

在C语言中,可以使用 signal 函数来设置信号的处理函数。例如:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>void handler(int signal)
{printf("i am process[%d],get a signal:%d\n",getpid(),signal);// 处理信号的代码
}
int main()
{int signo;// 设置 1~31信号 的处理函数为 sigint_handlerfor (signo = 1; signo <= 31; signo++){signal(signo, handler);}while (1){sleep(1);// 进程持续运行}return 0;
}

在这里插入图片描述

但是为什么不能捕捉 9 号信号呢?

  1. 9号信号(SIGKILL)是不能被捕捉的。这是因为SIGKILL信号是Linux系统中的一种特殊信号,它具有最高的优先级,并且无法被进程捕获、阻塞或忽略。当进程收到SIGKILL信号时,它会被立即终止,而无法执行任何处理逻辑。

  2. 这种设计是为了确保系统的稳定性和安全性。SIGKILL信号通常用于强制结束一些不响应或处于异常状态的系统进程,以防止它们对系统造成损害或影响其他进程的正常运行。因此,为了确保这种强制终止的执行,SIGKILL信号不能被捕获或修改其默认行为。

3.2 sigaction 函数

sigaction 函数是一种更为可靠和灵活的处理信号的方式,相较于 signal 函数,它提供了更多的控制选项。它允许指定处理函数、设置标志和提供可选的信号屏蔽。

   #include <signal.h>int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);The sigaction structure is defined as something like:struct sigaction {void     (*sa_handler)(int);void     (*sa_sigaction)(int, siginfo_t *, void *);sigset_t   sa_mask;int        sa_flags;void     (*sa_restorer)(void);};
示例
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>// SIGUSR1 信号处理函数
void sigusr1_handler(int signum) {printf("Received SIGUSR1 signal.\n");// 在这里执行与 SIGUSR1 相关的操作
}int main() {struct sigaction sa;// 设置 sa 结构体sa.sa_handler = sigusr1_handler;sa.sa_flags = 0;// 清空 sa_mask,即不阻塞任何其他信号sigemptyset(&sa.sa_mask);// 使用 sigaction 函数关联 SIGUSR1 信号和处理函数if (sigaction(SIGUSR1, &sa, NULL) == -1) {perror("Error setting up SIGUSR1 handler");exit(EXIT_FAILURE);}printf("My process ID: %d\n", getpid());printf("Waiting for SIGUSR1 signal...\n");while (1) {// 进程持续运行sleep(1);}return 0;
}

上述示例中我们使用了 sigaction 函数来设置对 SIGUSR1 信号的处理。struct sigaction 结构体用于指定信号处理函数及其他相关属性。在 main 函数中,我们设置了 sa_handler 为 sigusr1_handler,表示接收到 SIGUSR1 信号时执行这个处理函数。
上述示例中,我们还清空了 sa_mask,即不阻塞任何其他信号。如果你希望在信号处理期间阻塞某些其他信号,可以使用 sigaddset 等函数来设置 sa_mask。

此外,sa_flags 可以用来设置不同的标志,例如 SA_RESTART 用于指示系统调用在接收到信号后是否应该自动重启。

4. 信号阻塞

信号阻塞是指进程暂时屏蔽对某些信号的处理。在某些情况下,我们希望在处理一个信号时,暂时阻塞掉其他同类的信号,以确保处理的完整性。可以使用 sigprocmask 函数来设置信号阻塞。

#include <signal.h>// 阻塞 SIGINT 信号
sigset_t new_mask, old_mask;
sigemptyset(&new_mask);
sigaddset(&new_mask, SIGINT);
sigprocmask(SIG_BLOCK, &new_mask, &old_mask);// 执行一些需要阻塞 SIGINT 的操作// 恢复原信号屏蔽状态
sigprocmask(SIG_SETMASK, &old_mask, NULL);

示例

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>// SIGUSR1 信号处理函数
void sigusr1_handler(int signum) {printf("Received SIGUSR1 signal.\n");// 在这里执行与 SIGUSR1 相关的操作
}int main() {// 设置 SIGUSR1 信号处理函数signal(SIGUSR1, sigusr1_handler);printf("My process ID: %d\n", getpid());printf("Waiting for SIGUSR1 signal (blocked)...\n");// 创建一个集合来存储被阻塞的信号sigset_t block_mask;sigemptyset(&block_mask);  // 清空信号集// 将 SIGUSR1 加入到被阻塞的信号集中sigaddset(&block_mask, SIGUSR1);// 使用 sigprocmask 阻塞指定信号if (sigprocmask(SIG_BLOCK, &block_mask, NULL) == -1) {perror("Error blocking SIGUSR1");exit(EXIT_FAILURE);}// 在这里进行一些工作,期间 SIGUSR1 信号会被阻塞// 解除对 SIGUSR1 的阻塞if (sigprocmask(SIG_UNBLOCK, &block_mask, NULL) == -1) {perror("Error unblocking SIGUSR1");exit(EXIT_FAILURE);}printf("Waiting for SIGUSR1 signal (unblocked)...\n");while (1) {// 进程持续运行sleep(1);}return 0;
}

上述示例中,首先使用 sigemptyset 清空信号集,然后使用 sigaddset 将SIGUSR1
添加到被阻塞的信号集中。接着,使用 sigprocmask 函数将这个信号集应用到当前进程,从而阻塞了 SIGUSR1 信号。
在需要解除对信号的阻塞时,同样使用 sigprocmask 函数,但这次使用 SIG_UNBLOCK 标志。这样就解除了对
SIGUSR1 信号的阻塞。
这个过程演示了如何在程序运行过程中阻塞和解除阻塞指定的信号。在实际应用中,这种机制通常用于确保某些关键部分的原子性,防止信号中断影响程序的正常执行。

结语

通过本文,我们深入了解了Linux信号的基本概念、常见信号及其作用、信号的产生方式,以及信号的捕捉和阻塞。在编写和调试Linux应用程序时,对信号的理解是至关重要的,它为我们处理进程间通信和异常情况提供了强大的工具。希望本文能够帮助你更好地利用Linux信号机制。

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

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

相关文章

EM(Expectation-Maximum)算法

EM算法 简介 EM算法的核心分为两步 E步&#xff08;Expection-Step&#xff09;M步&#xff08;Maximization-Step&#xff09; 因为在最大化过程中存在两个参量 r , θ r,\theta r,θ&#xff0c;其中若知道 r r r&#xff0c;则知道 θ \theta θ&#xff1b;若知道 θ \…

机器学习之线性回归(Linear Regression)

概念 线性回归(Linear Regression)是机器学习中的一种基本的监督学习算法,用于建立输入变量(特征)与输出变量(目标)之间的线性关系。它假设输入变量与输出变量之间存在线性关系,并试图找到最佳拟合线来描述这种关系。 在简单线性回归中,只涉及两个变量:一个是自变量…

Go环境安装

目录 下载地址 安装 macos环境 window及其他环境 GOPROXY 非常重要 Go开发编辑器 下载地址 Go官网下载地址&#xff1a;https://golang.org/dl/ Go官方镜像站&#xff08;推荐&#xff09;&#xff1a;https://golang.google.cn/dl/ 选择要下载的系统版本&#xff1a; 安装 注意…

Github 2023-12-19开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2023-12-19统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目4Rust项目2非开发语言项目2C#项目1TypeScript项目1 Avalonia: 跨平台UI框架和Avalonia XPF 创建周…

弹幕情感分析可视化

弹幕情感分析可视化 引言1. 弹幕数据爬取2. 弹幕数据处理3. 弹幕数据可视化4. 弹幕情感分析5. 创新点&#xff1a;弹幕情感倾向分布 引言 当今互联网时代&#xff0c;大量的弹幕数据蕴含着丰富的信息&#xff0c;通过对这些数据进行分析和可视化&#xff0c;我们能够深入了解用…

端口占用命令 netstat (centos)+netstat (windows)

linux 1.使用 netstat 命令查看端口占用情况 netstat -tlnp 使用 -p 选项查看进程信息。 使用 -t 选项列出 TCP 协议的连接&#xff1a;类似&#xff08;使用 -u 选项列出 UDP 协议的连接&#xff1a;&#xff09; 2.查找占用指定端口号的应用信息 netstat -tlnp | grep 3…

输电线路定位:精确导航,确保电力传输安全

在现代社会中&#xff0c;电力作为生活的基石&#xff0c;其安全稳定运行至关重要。而输电线路作为电力传输的重要通道&#xff0c;其故障定位和修复显得尤为重要。恒峰智慧科技将为您介绍一种采用分布式行波测量技术的输电线路定位方法&#xff0c;以提高故障定位精度&#xf…

windows安装conda小环境 windows安装anaconda python jupyter anaconda

1 如果想体验在线版的jupyter&#xff0c;可以访问anaconda在Anaconda Cloud&#xff0c;需要注册github&#xff1a; 1 下载anaconda &#xff0c;并安装 1.1 下载 或者去清华镜像下载 Free Download | Anacondahttps://www.anaconda.com/downloadIndex of /anaconda/arch…

Excel只读模式带有密码,怎么办?

打开Excel文件之后发现是只读模式&#xff0c;并且excel只读模式是带有密码的&#xff0c;该如何取消带有密码的excel只读文件呢&#xff1f; 带有密码的只读模式&#xff0c;是设置了excel文件的修改权限&#xff0c;取消修改权限&#xff0c;我们需要先输入密码&#xff0c;…

Android-高效加载大图

Android 高效加载大图 前言读取位图尺寸和类型将按比例缩小的版本加载到内存中 前言 图片有各种形状和大小。在很多情况下&#xff0c;它们的大小超过了典型应用界面的要求。例如&#xff0c;系统“图库”应用会显示使用 Android 设备的相机拍摄的照片&#xff0c;这些照片的分…

windows下wsl(ubuntu)ldconfig报错

错误 sudo ldconfig /sbin/ldconfig.real: Cant link /usr/lib/wsl/lib/libnvoptix_loader.so.1 to libnvoptix.so.1 /sbin/ldconfig.real: /usr/lib/wsl/lib/libcuda.so.1 is not a symbolic link解决&#xff1a; 处理 sudo ldconfig 报错 libcuda.so.1 is not a symbolic …

简单几步完成SVN的安装

介绍以及特点 SVN&#xff1a;Subversion&#xff0c;即版本控制系统。 1.代码版本管理工具 2.查看所有的修改记录 3.恢复到任何历史版本和已经删除的文件 4.使用简单上手快&#xff0c;企业安全必备 下载安装 SVN的安装分为两部分&#xff0c;第一部分是服务端安装&…

pytorch文本分类(三)模型框架(DNNtextCNN)

pytorch文本分类&#xff08;三&#xff09;模型框架&#xff08;DNN&textCNN&#xff09; 原任务链接 目录 pytorch文本分类&#xff08;三&#xff09;模型框架&#xff08;DNN&textCNN&#xff09;1. 背景知识深度学习 2. DNN2.1 从感知器到神经网络2.2 DNN的基本…

源码编译 METIS 以及 GKlib 在Linux ubuntu上

1. GKlib 构建 $ git clone --recursive gitgithub.com:Kleenelan/GKlib.git $ cd GKlib/ $ make config ccgcc openmpset $ make $ make install源码构建了 GKlib 的 openmp 版本&#xff0c;以便充分使用多核的算力&#xff1b; make config ccgcc openmpset 的效果图&#…

鸿蒙端H5容器化建设——JSB通信机制建设

1. 背景 2023年鸿蒙开发者大会上&#xff0c;华为宣布为了应对国外技术封锁的潜在风险&#xff0c;2024年的HarmonyOS NEXT版本中将不再兼容Android&#xff0c;并推出鸿蒙系统以及其自研的开发框架&#xff0c;形成开发生态闭环。同时&#xff0c;在更高维度上华为希望将鸿蒙…

智能优化算法应用:基于黑猩猩算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于黑猩猩算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于黑猩猩算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.黑猩猩算法4.实验参数设定5.算法结果6.参考文…

音视频学习(二十一)——rtmp收流(tcp方式)

前言 本文主要介绍rtmp协议收流流程&#xff0c;在linux上搭建rtmp服务器&#xff0c;通过自研的rtmp收流库发起取流请求&#xff0c;使用ffmpegqt实现视频流的解码与播放。 关于rtmp协议基础介绍可查看&#xff1a;https://blog.csdn.net/www_dong/article/details/13102607…

【机器学习】卷积神经网络(CNN)的特征数计算

文章目录 基本步骤示例图解过程 基本步骤 在卷积神经网络&#xff08;CNN&#xff09;中&#xff0c;计算最后的特征数通常涉及到以下步骤&#xff1a; 确定输入尺寸&#xff1a; 首先&#xff0c;你需要知道输入数据的尺寸。对于图像数据&#xff0c;这通常是 (batch_size, c…

Webpack安装及使用

win系统 全局安装Webpack及使用 前提&#xff1a;使用Webpack必须安装node环境&#xff0c;建议使用nvm管理node版本。 1&#xff1a;查看自己电脑是否安装了node 2&#xff1a;npm install webpack版本号 -g 3&#xff1a;npm install webpack-cli -g -g:表示全局安装 4&…

龙芯loongarch64服务器编译安装gcc-8.3.0

前言 当前电脑的gcc版本为8.3.0,但是在编译其他依赖包的时候,出现各种奇怪的问题,会莫名其妙的中断编译。本地文章讲解如何自编译安装gcc,替换系统自带的gcc。 环境准备 下载页面:龙芯开源社区网站 - LoongArch GCC 8.3 交叉工具链 - 源码下载源码包名称如:loongson-gnu…