Linux:进程通信(三)信号的捕捉

目录

一、信号捕捉函数

1、signal函数

2、sigaction函数

二、用户态与内核态

1、用户态 

 2、内核态

用户态与内核态转换 

三、volatile关键字

四、SIGCHLD信号


一、信号捕捉函数

1、signal函数

signal函数是C语言标准库中的一个函数,用于处理Unix/Linux系统中的信号。信号是操作系统用于通知进程发生了某个事件的一种机制,比如用户按下Ctrl+C时发送的SIGINT信号,或者某些错误条件如除零错误产生的SIGFPE信号。signal函数允许程序定义对这些信号的响应方式,而不是采用默认行为(通常是终止进程)。

函数原型: 

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

参数说明:

  • signum:要处理的信号的编号,例如SIGINT(2号中断信号,通常是Ctrl+C),以及其它信号。
  • handler:处理函数的地址。这可以是以下几种形式:
    • SIG_DFL:恢复该信号的默认处理行为(通常是终止进程)。
    • SIG_IGN:忽略该信号。
    • 自定义函数:一个用户定义的函数指针,当信号发生时将调用该函数。该函数原型应为void function_name(int signum),其中signum是接收到的信号编号。

返回值:

signal函数返回与信号关联的先前处理函数的指针。如果之前没有安装处理函数,则返回值可能是SIG_ERR(表示发生错误)或者在某些实现中是默认的处理行为。

 这个函数在前面文章也使用过很多次,前面也对一些常用信号进行了说明,可以参考一下这篇文章:Linux:进程信号(一)信号的产生

2、sigaction函数

sigaction函数是POSIX标准中用于管理信号的高级接口,相比signal函数提供了更强大和灵活的信号处理能力。它允许程序不仅指定信号处理函数,还能控制信号处理时的其他方面,如信号掩码和额外的信号处理选项。

 函数原型: 

#include <signal.h>int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

参数说明:

  • signum:要操作的信号编号。
  • act:指向一个struct sigaction结构体的指针,用于设置新的信号处理行为。
  • oldact:指向另一个struct sigaction结构体的指针,用于存储以前的信号处理行为(如果不关心旧的行为,可以传入NULL)。

sigaction结构体:

struct sigaction {void     (*sa_handler)(int);      // 信号处理函数指针,兼容老版本void     (*sa_sigaction)(int, siginfo_t *, void *); // 新的、更强大的信号处理函数指针sigset_t   sa_mask;               // 处理该信号时需要阻塞的其他信号集合int        sa_flags;              // 信号处理的标志,如SA_RESTART, SA_NODEFER等// 可能还有其他平台相关的字段
};

信号处理函数:可以通过sa_handlersa_sigaction指定。如果使用sa_sigaction,则可以访问到更多关于信号的信息,如发送信号的进程ID和信号的具体原因。

信号掩码(sa_mask在信号处理函数执行期间,指定的信号将被临时阻塞,以避免递归或干扰信号处理过程。

标志(sa_flags:控制信号处理的额外行为,例如SA_RESTART可以让某些系统调用在被信号中断后自动重启,而SA_NODEFER可以防止在处理该信号时该信号被阻塞。

我们使用以下代码来测试一下:

#include<signal.h>
#include<iostream>
#include <sys/types.h>
#include <unistd.h>void printsigset(sigset_t *set)
{for(int i=31;i>=0;i--){if(sigismember(set,i)){std::cout<<"1";}else{std::cout<<"0";}}std::cout<<std::endl;
}
void handler(int signo)
{std::cout << "get a sig: " << signo << std::endl;sleep(20);}
int main()
{// sigset_t set,oset;// sigemptyset(&set);// sigemptyset(&oset);// sigaddset(&set,SIGINT);//屏蔽2号信号// sigaddset(&set,3);//屏蔽3号信号// sigaddset(&set,4);//屏蔽4号信号// sigaddset(&set,5);//屏蔽5号信号// sigprocmask(SIG_BLOCK,&set,&oset);struct sigaction act, oact;act.sa_handler=handler;sigemptyset(&act.sa_mask);sigaddset(&act.sa_mask,3);sigaction(2,&act,&oact);std::cout<<"pid"<<getpid()<<std::endl;while(true){sigset_t pending;sigpending(&pending);printsigset(&pending);sleep(1);}return 0;
}

运行可以看到:

 

先发出2号信号,这个时候向它发出三号信号时会被阻塞,并不会执行,因为在前面添加了三号信号的阻塞,当2号信号对应的handler结束时,才会被处理。

如果在未处理2号信号时,直接发送3号信号,那么会直接终止:

如果有处理函数(通过上述方式注册),内核会执行以下操作:

保存现场:保存当前程序上下文,包括寄存器状态等,以便稍后恢复执行。

修改信号掩码通常,在执行信号处理函数之前,内核会临时修改进程的信号掩码,以防止在处理信号过程中被相同的或其他信号打断,除非这些信号被特别设置为不阻塞。

调用信号处理函数执行用户定义的信号处理函数。在此期间,进程处于用户态。

恢复现场:信号处理完毕后,内核恢复之前保存的程序上下文,进程从被中断的地方继续执行,或者根据信号处理函数的返回情况和系统调用的重启规则决定后续动作。

二、用户态与内核态

用户态(User Mode)和内核态(Kernel Mode),也称为用户空间和内核空间,是现代操作系统中的两种处理器执行模式,它们定义了程序运行时的不同权限级别和访问能力。

1、用户态 

在用户态下,程序(通常是应用程序)只能执行非特权指令,不能直接访问硬件资源或执行对系统稳定性有风险的操作。这意味着程序不能直接读写内存、操作外设、更改系统时间等。

应用程序的大部分时间都在用户态下运行,这样可以保证系统的安全性和稳定性,因为程序错误不会直接影响到操作系统的核心部分。

如果用户态程序需要执行如磁盘I/O、网络通信等操作,它必须通过系统调用(System Call)向操作系统请求服务,这时就会从用户态转换到内核态。

 2、内核态

内核态下,程序可以执行所有指令,包括特权指令,可以直接访问和控制所有系统资源,如内存、I/O设备等。操作系统内核及其相关模块(如设备驱动程序)在内核态下运行,负责管理系统资源、处理中断、调度进程等核心任务。

当系统调用发生时,CPU从用户态切换到内核态,操作系统内核执行所需的服务,并在完成后返回用户态。这一过程涉及到堆栈的切换、权限级别的变化和上下文的保存与恢复。

内核态还负责处理硬件中断和异常,无论当前处理器处于何种状态,一旦中断或异常发生,CPU都会立即进入内核态以处理这些事件。

用户态与内核态转换 

转换通常由硬件支持,并由操作系统控制。从用户态到内核态的转换通常是通过执行特定指令(如系统调用指令)、产生中断或异常来触发。

从内核态返回用户态通常发生在系统调用完成、中断处理结束或异常处理完成后,操作系统通过执行相应的返回指令来实现状态的恢复。

这种区分和转换机制是操作系统设计的基础之一,旨在提供隔离和保护,确保系统稳定性和安全性,同时允许用户程序有效利用系统资源。

三、volatile关键字

volatile关键字在C/C++等编程语言中是一个类型修饰符,用于指示编译器不要对被修饰的变量进行任何优化假设,确保程序的执行符合预期,特别是在多线程编程和硬件交互场景中。

四、SIGCHLD信号

        wait和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非阻塞地查询是否有子进程结束等待清理(也就是轮询的方式)。采用第一种方式,父进程阻塞了就不能处理自己的工作了;用第二种方式,父进程在处理自己的工作的同时还要记得时不时地轮询一 下,程序实现复杂。

        子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。

僵尸进程:

运行以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include<sys/types.h>
#include<unistd.h>
void handler(int sig)
{pid_t id;while( (id = waitpid(-1, NULL, WNOHANG)) > 0){printf("wait child success: %d\n", id);}printf("child is quit! %d\n", getpid());
}
int main()
{signal(SIGCHLD, handler);pid_t cid;if((cid = fork()) == 0){//childprintf("child : %d\n", getpid());sleep(3);exit(1);}while(1){printf("father proc is doing some thing!\n");sleep(1);}waitpid(-1, NULL, WNOHANG);return 0;
}
可以看到不会生成僵尸进程,因为一旦退出就立马回收
不产生僵尸进程还有另外一种办法 : 父进程调用 sigaction SIGCHLD 的处理动作置为SIG_IGN, 这样 fork 出来的子进程在终止时会自动清理掉 , 不 会产生僵尸进程 , 也不会通知父进程。系统默认的忽略动作和用户用sigaction 函数自定义的忽略通常是没有区别的, 但这是一个特例。此方法对于 Linux 可用 , 但不保证在其它UNIX 系统上都可用。
监视发现这样也不会产生僵尸进程:
信号捕捉的过程确保了信号能够灵活且有效地传递给进程,同时允许进程以自定义的方式响应这些信号,从而增强了程序的健壮性和灵活性。

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

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

相关文章

Ps 滤镜:其它

Ps菜单&#xff1a;滤镜/其它 Filter/others “其它”子菜单中的滤镜允许创建自己的滤镜、使用滤镜修改蒙版、在图像中使选区发生位移和快速调整颜色。 HSB/HSL HSB/HSL 主要用于实现 RGB、HSB 及 HSL 三种模型的相互转换。 比如&#xff0c;当执行本滤镜从 RGB 转换为 HSB 之后…

YOLOv8网络结构介绍

将按照YOLOv8目标检测任务、实例分割任务、关键点检测任务以及旋转目标检测任务的顺序来介绍&#xff0c;主要内容也是在目标检测任务中介绍&#xff0c;其他任务也只是Head层不相同。 1.YOLOv8_det网络结构 首先&#xff0c;YOLOv8网络分成了三部分&#xff0c;分别是主干网络…

接口信息解析

在进行浏览器网站的接口测试时&#xff0c;需要解析以下关键信息以确保接口的正确性和性能&#xff1a; 1. 接口地址&#xff08;URL&#xff09;&#xff1a; 接口的地址是测试的基础&#xff0c;包括接口的协议&#xff08;如 HTTP 或 HTTPS&#xff09;、主机名、端口&…

自动控制原理学习--平衡小车的控制算法(三)

上一节PID的simulin仿真&#xff0c;这一节用LQR 一、模型 二、LQR LQR属于现代控制理论的一个很重要的点&#xff0c;这里推荐B站的【Advanced控制理论】课程&#xff08;up主DR_CAN&#xff09;&#xff0c;讲得很好&#xff0c;这里引用了他视频里讲LQR的ppt。 LQR属于lo…

(三)小程序样式和组件

视频链接&#xff1a;尚硅谷2024最新版微信小程序 文章目录 小程序的样式和组件介绍样式-尺寸单位 rpx样式-全局样式和局部样式组件-组件案例演示组件案例-轮播图区域绘制组件案例-轮播图图片添加组件案例-绘制公司信息区域组件案例-商品导航区域组件案例-跳转到商品列表组件案…

python爬取sci论文等一系列网站---通用教程超详细教程

环境准备 确保安装了Python以及requests和BeautifulSoup库。 pip install requests beautifulsoup4确定爬取目标 选择一个含有SCI论文的网站&#xff0c;了解该网站的内容布局和数据结构。 &#xff08;1&#xff09;在浏览器中访问目标网站&#xff0c;右键点击页面并选择…

案例研究|硬之城借助DataEase以数据驱动供应链精细化管理

深圳硬之城信息技术有限公司&#xff08;以下简称为“硬之城”&#xff09;成立于2015年&#xff0c;专注电子元件供应链领域&#xff0c;定位于电子产业供应链与智造平台。硬之城通过名为“Allchips”的集成式服务平台&#xff0c;为客户提供一站式的电子元件采购和供应链管理…

VTK 建模方法:建模基础

VTK 建模方法&#xff1a;建模基础 VTK 建模方法&#xff1a;建模基础VTK 中模型的表达实例1&#xff1a;自定义 vtkPolyData实例2&#xff1a;vtkTubeFilter实例3&#xff1a;vtkImplicitModeller实例4&#xff1a;vtkRegularPolygonSource实例5&#xff1a;vtkWarpTo VTK 建模…

如何在mac电脑安装 Android SDK

1、在 Mac 电脑上安装 Android SDK 的步骤如下: 前往 Android 开发者网站下载 Android SDK 打开 Android 开发者网站 (https://developer.android.com/studio) 打开下载好的 Android SDK 安装包 2、解压 Android SDK 安装包 打开下载好的 Android SDK 安装包 将 android-…

深度主动学习(Deep Active Learning)——基于pytorch和ALipy工具包实现双向GRU模型

前言 在ALipy的官网说ALipy只支持sklearn和tensorflow模型&#xff0c;模型对象应符合 scikit-learn api。 但是alipy提供了ToolBox的工具箱&#xff0c;里面包装了多种查询策略&#xff0c;计算指标等工具&#xff0c;几乎具有Alipy的全部功能&#xff0c;虽然不能使用ALipy提…

Pycharm2024版,更换安装源

1、选择Python Packages 2、点击图中的小齿轮 3、点击 号 4、添加源地址 常用源如下&#xff1a; 清华&#xff1a;https://pypi.tuna.tsinghua.edu.cn/simple 阿里云&#xff1a;http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn…

HTML5 Canvas发光Loading动画特效源码

源码介绍 之前我们分享过很多基于CSS3的Loading动画效果&#xff0c;相信大家都很喜欢。今天我们要来分享一款基于HTML5 Canvas的发光Loading加载动画特效。Loading旋转图标是在canvas画布上绘制的&#xff0c;整个loading动画是发光3D的视觉效果&#xff0c;HTML5非常强大。 …

索引失效情况

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;面经 ⛺️稳中求进&#xff0c;晒太阳 一、索引列上运算操作。 不要在索引列上进行运算操作&#xff0c;否则索引会失效。 在tb_user的phone列加上索引&#xff0c;然后进行条件查询&am…

nginx自动部署-跨操作系统

项目里面有一个需求&#xff0c;就是需要用让nginx进程提供给系统管理一个start,stop和getPid方法&#xff0c;这样系统管理可以自动拉起来nginx&#xff0c;达到自动部署的目的。离线部署同样适用 这样一来&#xff0c;我就需要提供windows版本linux不同版本的nginx源码包&am…

解决Vue devtools插件数据变化不会自动刷新

我们使用devtools插件在监测vuex中表单或自定义组件的数据&#xff0c;发现页面数据发生变化后&#xff0c;但是devtools中还是老数据&#xff0c;必须手动点击devtools刷新才能拿到最新的数据。很烦&#xff01; 解决方案&#xff1a; 打开chrome的设置&#xff0c;向下翻&…

JavaEE企业级开发中常用的Stream流

介绍 在Java编程中&#xff0c;Stream流是Java 8引入的一个重要概念&#xff0c;它提供了一种新的处理集合的方式&#xff0c;可以更加简洁、高效地进行数据操作。Stream流支持各种常见的操作&#xff0c;比如过滤、映射、排序、聚合等&#xff0c;同时也支持并行处理&#xf…

自学错误合集--MessageSource国际化接口

java后端自学错误总结 一.MessageSource国际化接口总结 一.MessageSource国际化接口 今天第一次使用MessageSource接口,比较意外遇到了一些坑 messageSource是spring中的转换消息接口&#xff0c;提供了国际化信息的能力。MessageSource用于解析 消息&#xff0c;并支持消息的…

软件项目管理期末复习题8-16章

第八章软件项目质量计划 一、填空题 1、&#xff08;审计&#xff09;是对过程或产品的一次独立质量评估。 2、质量成本包括预防成本和&#xff08;缺陷成本&#xff09;。 3、&#xff08;软件质量&#xff09;是软件满足明确说明或者隐含的需求的程度。 5、McCall质量模…

【华为】IPSec VPN手动配置

【华为】IPSec VPN手动配置 拓扑配置ISP - 2AR1NAT - Easy IPIPSec VPN AR3NATIPsec VPN PC检验 配置文档AR1AR2 拓扑 配置 配置步骤 1、配置IP地址&#xff0c;ISP 路由器用 Lo0 模拟互联网 2、漳州和福州两个出口路由器配置默认路由指向ISP路由器 3、进行 IPsec VPN配置&…

数据的输入和输出

早期的总线系统 为了解决通信的问题、主板上铺设了一条公共线路、各个设备都连接到这条线路上、不管谁要和谁通信、都能使用它来传输、这条线路就是总线。 总线上有CPU、内存、鼠标、键盘、硬盘、网卡、声卡、显卡等… 说是一条总线、实际上是包含了传输数据的数据总线、传输…