【Linux】进程信号,相关函数的简单实用

news/2024/2/25 12:50:04/文章来源:https://blog.csdn.net/qq_62407309/article/details/135621519

文章目录

  • 一、讨论范围
  • 二、信号的结构
    • 1.信号的本质
    • 2.预备知识
      • 2.1 如何发送信号
      • 2.2 如何查看后台程序
  • 三、改变信号默认触发方式的两个函数
    • 1.signal
    • 2.sigaction
  • 四、信号集操作函数和相关指令
    • 0.sigprocmask
    • 1.sigemptyset
    • 2.sigaddset
    • 3.sigdelset
    • 4.sigfillset
  • 总结



一、讨论范围

在这里插入图片描述

  • 编号34以上的信号叫做实时信号,不在讨论范围内
  • 上图中信号的产生方式和默认处理动作可以通过
    man 7 signal指令来查看

二、信号的结构

1.信号的本质

task_struct内部存在一个位图结构,用int表示:uint32_t signals;
0000 0000 0000 0000 0000 0000 0000 0000

所谓的发送信号其实就是修改特定进程信号位图的特定比特位

  • 比特位的位置就是信号的编号
  • 比特位的内容表示1是否收到信号

2.预备知识

2.1 如何发送信号

kill options PID
其中,PID是进程的ID,可以是单个进程的ID,也可以是多个进程的ID,用空格分隔

eg:
给ID为1234的进程发送2号信号
kill -2 1234

该处使用的url网络请求的数据。

2.2 如何查看后台程序

ps aux | grep 名称关键词

eg:
查找名称与“chrome”相关的后台程序
ps aux | grep chrome


三、改变信号默认触发方式的两个函数

举个例子,在我们不小心写出死循环,或者故意写出死循环以便于使程序持续运行的时候,通常会在命令行输入“Ctrl+C”来停止命令行的无限刷屏,而我们输入的“Ctrl+C”,实际上就是给我们提到的死循环程序发送了2号信号;
下面是两个函数,它们的功能可以让一个程序在接收到2号信号时继续运行,而不是就此退出

1.signal

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

功能为“在收到signum号信号的时候执行handler函数”

eg:signal(2,handler) signal(SIGQUIT,handler)
两种写法都可以,signum可以是除了SIGKILL和SIGSTOP以外的任何有效信号

示例代码:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sigcb()
{printf("SIGINT\n");
}
int main()
{signal(SIGINT,(sighandler_t)sigcb);while(1){printf("m alive\n");sleep(2);}return 0;
}

运行结果:
在这里插入图片描述
按下“Ctrl+C”也会有类似的结果
在这里插入图片描述

自己想试一下的话后面可以用“Ctrl+Z”结束这个程序,向它发送9号信号也可以,因为SIGKILL和SIGSTOP这个两个信号不能被系统忽略,也不能被改变默认处理动作

man一下之后可以发现使用文档表示这个函数已经过时了,而且不同系统版本下signal函数的功能也可能不一样

2.sigaction

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

也是用来改变进程对于已接收信号做出的行动;
signum可以是任何除了SIGKILL和SIGSTOP以外的有效信号;
如果act不是NULL,则从act安装信号signum的新动作。如果oldact不是NULL,先前的操作保存在oldact中。

所以为了使用这个函数,struct sigaction的结构也必须了解

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);};
  • sa_handler就是接收到signum信号以后被调用的新方法,使用的时候先声明一个这样的结构体,然后再把函数指针指向你想要的函数就好了
  • 不要同时给sa_handler和sa_sigaction同时赋值
  • sa_restorer这个成员已经过时了,别用
  • 如果sa_flags被指定为SA_SIGINFO,收到signum对应的信号以后就执行sa_sigaction指向的函数(sa_handler这时候就没用了),这个函数把int作为其第一个参数,一个指向siginfo_t的指针作为其第二个参数,并将指向ucontext_t(强制转换为void *)的指针作为其第三个参数。(通常,handler函数不使用第三个参数)
  • sa.sa_flags = 0; 表示将 sa_flags 字段设置为零,表示使用默认的标志位,即默认的信号处理行为。

示例代码:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sigcb(int m)//为了不报错所以弄成了和结构体中指针相匹配的类型
{printf("SIGINT\n");
}
int main()
{struct sigaction m;m.sa_handler=sigcb;sigaction(SIGINT,&m,NULL);while(1){printf("m alive\n");sleep(1);}return 0;
}

运行结果:
在这里插入图片描述

四、信号集操作函数和相关指令

这里的“信号集操作函数”指的就是用来操作signal mask的函数;
在 Unix 系统中,每个进程都有一个信号掩码signamask,用于管理它希望阻塞或允许传递的信号。sigprocmask 函数允许程序员操作这个信号掩码,以便选择性地阻塞或解除阻塞特定的信号。

#include <signal.h>

用起来也是事先声明好一个sigset_t类型的信号集``

0.sigprocmask

int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

oldset用来存储set的前一个值,也就是说如果oldset为非null,则信号掩码的前一个值存储在oldset中。
如果set为NULL,则信号掩码不变(忽略how),信号掩码的当前值仍然在oldset中返回(如果oldset不是的话)
参数how的参数:
在这里插入图片描述

1.sigemptyset

int sigemptyset(sigset_t *set);

函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。

2.sigaddset

int sigaddset (sigset_t *set, int signo);

添加一个signo信号到set这个信号集里面,使signo这个信号变成可以接收到的有效信号

3.sigdelset

int sigdelset(sigset_t *set, int signo);

把set信号集里面的signo信号删了

4.sigfillset

int sigfillset(sigset_t *set);

函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系
统支持的所有信号。

示例代码:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int main()
{sigset_t tmp;sigemptyset(&tmp);sigaddset(&tmp,2);sigaddset(&tmp,40);sigprocmask(SIG_BLOCK,&tmp,NULL);while(1){printf("m alive\n");sleep(1);}return 0;
}

把2号信号和40号信号都屏蔽了,然后再向test3发送这两个信号,发现什么事也没有发生:
在这里插入图片描述


总结

之前那篇讲共享内存的博客相对来说数据比较好,原因可能是我是读了man的使用手册以后按我理解的逻辑顺序讲的,而且我个人认为使用文档里对函数的说明比博客和百度要全面一些
有一些函数因为使用文档太长了所以我只挑了比较重要的部分来讲,如有遗漏欢迎指出
感谢支持

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

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

相关文章

Android的setContentView流程

一.Activity里面的mWindow是啥 在ActivityThread的performLaunchActivity方法里面&#xff1a; private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {ActivityInfo aInfo r.activityInfo;if (r.packageInfo null) {r.packageInfo getP…

重学Java 7 数组Arr.1

我欲与君相知&#xff0c;长命无绝衰 ——24.1.16 一、数组的定义 1.概述&#xff1a;数组是一个容器&#xff0c;数组本身属于引用数据类型 2.作用&#xff1a;一次存储多个数据 3.特点&#xff1a; ①既可以存储基本类型的数据&#xff0c;也可以存储引用类型的数据 ②定长&a…

ACL【新华三与华为的区别】

【解释】acl简单点解释就是&#xff0c;一套根据需求而设置的规则 【背景】 192.168.1.0/24 网段不允许访问 192.168.2.0/24 网段&#xff0c;要求使用基本 ACL 实现20_1 可以访问 20_6 的 TELNET 服务&#xff0c;但不能访问 FTP 服务 【操作步骤】 {易混点 }&#xff1a;1. …

06--视图、索引、事务、权限

1、视图(view) 1.1 什么是视图 视图是一种根据查询&#xff08;也就是SELECT表达式&#xff09;定义的数据库对象&#xff0c;用于获取想要看到和使用的局部数据 视图有时也被成为“虚拟表”。 视图可以被用来从常规表&#xff08;称为“基表”&#xff09;或其他视图中查询…

k8s 存储卷和pvc,pv

存储卷---数据卷 容器内的目录和宿主机的目录进行挂载。 容器在系统上的生命周期是短暂的&#xff0c;deletek8s用控制器创建的pod&#xff0c;delete相当于重启&#xff0c;容器的状态也会回复到初始状态。 一旦回到初始状态&#xff0c;所有的后天编辑的文件的都会消失。 …

PySide6/PyQt6如何设置全局热键,全局热键!

文章目录 📖 介绍 📖🏡 环境 🏡📒 实现方法 📒⚓️ 相关链接 ⚓️📖 介绍 📖 我们在使用PySide6/PyQt6设置热键的时候一般都是使用QShortcut,、QKeySequence两个类来实现,但是这样写的快键键并不是全局快捷键,需要用户激活软件窗口才能实现快捷键对应的功能,…

【面试合集】说说微信小程序的发布流程?

面试官&#xff1a;说说微信小程序的发布流程&#xff1f; 一、背景 在中大型的公司里&#xff0c;人员的分工非常仔细&#xff0c;一般会有不同岗位角色的员工同时参与同一个小程序项目。为此&#xff0c;小程序平台设计了不同的权限管理使得项目管理者可以更加高效管理整个团…

数据结构【树+二叉树】

目录 线性表和非线性表 树的概念 树的存储表示 二叉树的概念 特殊二叉树 满二叉树 完全二叉树 二叉树的性质 二叉树的存储结构 顺序存储 链式存储 本篇我们开始进入数据结构中【树】的学习。 线性表和非线性表 逻辑结构&#xff1a;人想象出来的物理结构&#xf…

css 怎么绘制一个带圆角的渐变色的边框

1&#xff0c;可以写两个样式最外面的div设置一个渐变的背景色。里面的元素使用纯色。但是宽高要比外面元素的小。可以利用里面的元素设置padding这样挡住部分渐变色。漏出来的渐变色就像边框一样。 <div class"cover-wrapper"> <div class"item-cover…

MongoDB-数据库文档操作(2)

任务描述 文档数据在 MongoDB 中的查询和删除。 相关知识 本文将教你掌握&#xff1a; 查询文档命令&#xff1b;删除文档命令。 查询文档 我们先插入文档到集合 stu1 &#xff1a; document([{ name:张小华, sex:男, age:20, phone:12356986594, hobbies:[打篮球,踢足球…

【软件测试】学习笔记-测试基础架构

这篇文章探讨什么是测试基础架构。 什么是测试基础架构&#xff1f; 测试基础架构指的是&#xff0c;执行测试的过程中用到的所有基础硬件设施以及相关的软件设施。因此&#xff0c;我们也把测试基础架构称之为广义的测试执行环境。通常来讲&#xff0c;测试基础 架构主要包括…

【PostgreSQL内核学习(二十三)—— 执行器(ExecEndPlan)】

执行器&#xff08;ExecEndPlan&#xff09; 概述ExecEndPlan 函数ExecEndNode 函数 总结 声明&#xff1a;本文的部分内容参考了他人的文章。在编写过程中&#xff0c;我们尊重他人的知识产权和学术成果&#xff0c;力求遵循合理使用原则&#xff0c;并在适用的情况下注明引用…

压力测试+接口测试(工具jmeter)

jmeter是apache公司基于java开发的一款开源压力测试工具&#xff0c;体积小&#xff0c;功能全&#xff0c;使用方便&#xff0c;是一个比较轻量级的测试工具&#xff0c;使用起来非常简单。因 为jmeter是java开发的&#xff0c;所以运行的时候必须先要安装jdk才可以。jmeter是…

opencv-4.8.0编译及使用

1 编译 opencv的编译总体来说比较简单&#xff0c;但必须记住一点&#xff1a;opencv的版本必须和opencv_contrib的版本保持一致。例如opencv使用4.8.0&#xff0c;opencv_contrib也必须使用4.8.0。 进入opencv和opencv_contrib的github页面后&#xff0c;默认看到的是git分支&…

DC电源模块与AC电源模块的对比分析

DC电源模块与AC电源模块的对比分析 BOSHIDA DC电源模块和AC电源模块是两种常见的电源模块&#xff0c;它们在供电方式、稳定性、适用范围等方面有所不同&#xff0c;下面是它们的对比分析&#xff1a; 1. 供电方式&#xff1a; DC电源模块通过直流电源供电&#xff0c;通常使用…

shiro实战

接下来我将用编码的方式&#xff0c;来演示如何使用shirojwt实现认证并下发token&#xff0c;但是没有整合到springboot中。只是shiro的API的调用 1. shirojwt 实现登录认证、获取资源的流程图 2.编码实现 &#xff08;1&#xff09;工程结构 &#xff08;2&#xff09;核心代…

msvcr110.dll缺失怎么解决,修复msvcr110.dll缺失的方法分享

首先&#xff0c;我们来了解一下msvcr110.dll是什么文件。msvcr110.dll是Microsoft Visual C 2012 Redistributable的一个组件&#xff0c;它包含了许多运行库函数&#xff0c;这些函数在编译和运行使用Visual C编写的程序时是必不可少的。简单来说&#xff0c;msvcr110.dll就是…

Unity解决Udp客户端无法接收数据的问题

Unity解决Udp客户端无法接收数据的问题 在我之前做过的项目中&#xff0c;其中不少涉及Udp客户端的项目。在这些项目中&#xff0c;一般只需要实现客户端向服务器端发送数据的功能就可以了&#xff0c;一般都不用接收服务器端发送的数据&#xff0c;但是也有同学使用了我分享的…

[C#]winform部署官方yolov8-obb旋转框检测的onnx模型

【官方框架地址】 https://github.com/ultralytics/ultralytics 【算法介绍】 Yolov8-obb&#xff08;You Only Look Once version 8 with Oriented Bounding Boxes&#xff09;是一种先进的对象检测算法&#xff0c;它在传统的Yolov3和Yolov4基础上进行了优化&#xff0c;加…

Next.js 开发指​南(GitHub 115k star​)

Next.js 是一个构建于 Node.js 之上的开源 Web 开发框架&#xff0c;它扩展了最新的 React 特性&#xff0c;集成了基于 Rust 的 JavaScript 工具&#xff0c;可以帮助你快速创建全栈 Web 应用 &#xff08;full-stack Web applications&#xff09; 。 对于有一定 React 基础…