信号

信号也是IPC中的一种,是和管道,消息队列,共享内存并列的概念。

本文参考:

Linux中的信号_linux中信号_wolf鬼刀的博客-CSDN博客

Linux系统编程(信号处理 sigacation函数和sigqueue函数 )_花落已飘的博客-CSDN博客

Linux的sigqueue函数_linux sigqueue_QtHalcon的博客-CSDN博客

概念

信号是进程之间异步通知的一种方式,属于软中断;

可以使用“kill -l”来查看系统定义的信号列表:

 在这里插入图片描述

所以,当在终端输入“crtl + c”时,其实就是调用了2号SIGINT,使用信号机制停止了一个程序。

  • 从图中可以看到每个信号都有一个编号宏定义的名称,这些宏都可以在signal.h中找到
  • 注意并不是一共有64个信号,自己仔细看,共有62种信号
  • 31号信号之前都是不可靠信号,也是非实时信号
  • 编号34以上的是实时信号,可靠信号,各种信号各自在什么条件下产生什么默认的动作都可以在signal(7)中查看

同时kill命令还可以用来执行命令,例如一个进程的PID号为1234,则可以使用“kill 9 1234”或“kill SIGKILL 1234” 来杀死这个进程

另外,kill不仅可以使用在命令窗口,kill还可以作为一个API

kill函数 : 给一个指定的进程发送一个指定的信号

包含的头文件:

#include <sys/types.h>
#include <signal.h>

函数原型:

int kill(pid_t pid, int sig);

函数参数:

  • pid:进程号
  • sig:信号编号

信号的处理方式

  • 忽略信号(SIGKILL和SIGSTOP无法被忽略
  • 执行给信号的默认动作
  • 提供一个信号处理函数,要求用户在处理该信号时切换到用户态去执行处理函数,即捕捉信号

其中,对于用户来说,信号更多的意义是实现异步操作,也就是捕捉信号,其核心就是编写“信号处理函数”

信号处理的API函数及应用

signal函数

用来自定义信号处理方式

需要包含的库

#include <signal.h>

函数原型

typedef void (*sighandler_t)(int); //一个指向“传入参数是int 返回值是void的函数”,名为“sighandler_t”的指针sighandler_t signal(int signum, sighandler_t handler);

函数参数

  • signum:信号编号
  • handler:函数指针,指向信号处理函数;也可以使用宏,比如使用“SIG_IGN”,则忽略信号

使用举例1

signal1.c:
#include <signal.h>
#include <stdio.h>void sighandler(int sig)
{printf("get signal:%d\n",sig);}int main()
{signal(2,sighandler);while(1);return 0;
}

可见,当捕获了信号2之后,在键盘输入“ctrl + c” 不再会执行默认动作来结束进程,而是被程序捕获,并执行了信号处理函数

那么此时如何退出进程呢?可以使用刚刚提到的kill指令,先搜索pid号然后直接杀死进程

 

使用举例2 

同样,也可以在程序中直接调用kill函数来发送信号

signal2.c:

编写一个C程序实现“向自己发送指定信号”的功能

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>void sighandler(int sig)
{printf("get signal:%d\n",sig);}int main(int argc,char **argv)
{int signum;pid_t pid;signum = atoi(argv[1]); //由于从键盘接收的是字符串,所以要使用“atoi”函数将ASCII码转为整型数pid = getpid();signal(2,sighandler); //为了实现效果,一定要先执行signal,再执行killkill(pid,signum);while(1);return 0;
}

编译运行代码并指定第二个参数为2: 

 

可见,虽然此时没有在键盘打出 “ctrl + c”,但是内部的代码调用了kill对自己发送了2号信号,所以同样实现了刚刚的效果。

学到了这里,一定会产生疑问:为什么信号会作为IPC中的一员,如果只是发送信号的话,不应该算是一种很有效的进程通讯方式,所以信号的处理还有更高级的方法,也就是带消息的高级信号操作,既然要带消息,那么就需要使用更高级的API函数来实现收发:

  • 发送信号:使用sigqueue函数
  • 接收信号:使用sigaction函数

sigaction函数

实现带消息的高级信号操作,可以接收带消息的信号

需要包含的库

#include <signal.h>

函数原型

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

函数参数

  • signum:信号编号
  • act:指定新的信号处理方式
  • oldact:输出先前信号的处理方式(如果不为NULL的话)

struct sigaction结构体介绍(sigaction函数的第二个参数)

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:此参数和signal()的参数handler相同,代表新的信号处理函数,如果使用这个成员参数,那就和signal函数无异了
  • sa_sigaction:带消息的信号处理函数

int:第一个参数是信号编号

siginfo_t *:第二个参数是一个结构体,包括si_signo,si_code,si_int,si_value等等各种成员,其中si_signo和si_code必须实现

void *:第三个参数是一个指针,用来指示是否有消息存在,如果为NULL则无消息,否则就有消息

  • sa_mask:用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置,可以理解为处理信号的时候释放阻塞(默认阻塞)
  • sa_flags:用来设置信号处理的其他相关操作,可以是以下值的“按位或”组合:

 ◆ SA_RESTART:使被信号打断的系统调用自动重新发起
 ◆ SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号
 ◆ SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程
 ◆ SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号
 ◆ SA_RESETHAND:信号处理之后重新设置为默认的处理方式
 ◆ SA_SIGINFO:使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数(重要

  • re_restorer:是一个已经废弃的数据域,不使用 

sigqueue函数

发送带消息的信号

成功使用sigqueue这个函数需要有两个前提:

  • sigaction函数的第二个参数结构体中的sa_flags成员必须有“SA_SIGINFO
  • sigaction函数的第二个参数结构体中实现的是成员sa_sigaction函数而不是成员sa_handler函数

需要包含的库

#include <signal.h>

函数原型

int sigqueue(pid_t pid, int sig, const union sigval value);

函数参数 

  • pid:目标进程的进程号
  • sig:要发送的信号的编号
  • value:要附带发送的消息

value的类型是一个名为sigval的联合体,如果需要附带的消息是整型,则将数据存入成员“sival_int”;而如果消息类型是字符串,则存入成员“sival_ptr"

union sigval {int   sival_int;void *sival_ptr;
};

使用sigaction和sigqueue的实操演示

需求:编写两个C程序,一个使用sigaction来接收,一个使用sigqueue来发送,实现带消息的信号的通讯

signal3.c:(接收带消息的信号)

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>void sighandler(int sig, siginfo_t *info, void *context)
{printf("get signal:%d\n",sig);if(context != NULL){printf("get data = %d\n",info->si_int);//printf"(get data = %d\n",info->si_value.sival_int);}}int main()
{struct sigaction act;act.sa_sigaction = sighandler;act.sa_flags = SA_SIGINFO;sigaction(2,&act,NULL);while(1);return 0;
}

signal4.c:(发送带消息的信号)

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>int main(int argc,char **argv)
{int signum;pid_t pid;int data;pid = atoi(argv[1]);signum = atoi(argv[2]);data = atoi(argv[3]);union sigval value;value.sival_int = data;	sigqueue(pid,signum,value);printf("signal no.%d has been sent to pid %d, context:%d\n",signum,pid,data);return 0;
}

实现效果:

 首先编译并运行signal3.c

可见,此时没有接收到任何信号,一直阻塞

此时新开一个窗口先查询到这个signal3.c的进程号

然后根据进程号,编译并运行signal4.c,将编号为2的信号发送到signal3.c对应的进程,并附带55的整型消息

此时再回看signal3.c的运行界面 

 

可见,此时不仅收到了来自signal4.c的信号,还收到了附带的整型数据消息 

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

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

相关文章

常用curl参数及样例讲解

1 缘起 后端/后台项目开发过程中&#xff0c;有两个阶段的接口测试和验证&#xff0c;自测阶段&#xff0c;通过Postman构建请求&#xff0c; 自建一些参数&#xff0c;测试功能以及边界条件&#xff0c;这些都是可以自行掌控的&#xff0c;当完成功能验证与前端对接时&#x…

19万字智慧城市总体规划与设计方案WORD

导读&#xff1a;原文《19万字智慧城市总体规划与设计方案WORD》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 感知基础设施 感知基础设施架构由感知范围、感知手…

正演的数值模拟(零基础,学习中)

摘要: 本贴从零开始学习正演的数值模拟方法. 1. 偏微分基础 引例: 物体从一维坐标的原点开始移动, 在 t t t 时刻, 它在坐标轴的位置由函数 s ( t ) s(t) s(t) 确定, 则速度为位置变化量与时间的比值: v ( t ) d s ( t ) d t lim ⁡ Δ t → 0 s ( t Δ t ) − s ( t )…

19-普通组件的注册使用

普通组件的注册使用-局部注册 一. 组件注册的两种方式:1.局部注册:只能在注册的组件内使用 (1) 创建 vue 文件(单文件组件) (2) 在使用的组件内导入,并注册 components:{ 组件名: 组件对象 } // 导入需要注册的组件 import 组件对象 from.vue文件路径 import HmHeader from ./…

使用 HTML、CSS 和 JavaScript 创建实时 Web 编辑器

使用 HTML、CSS 和 JavaScript 创建实时 Web 编辑器 在本文中&#xff0c;我们将创建一个实时网页编辑器。这是一个 Web 应用程序&#xff0c;允许我们在网页上编写 HTML、CSS 和 JavaScript 代码并实时查看结果。这是学习 Web 开发和测试代码片段的绝佳工具。我们将使用ifram…

如何找到一个数的所有质因数,以及如何快速判断一个数是不是质数

前情介绍 今天遇到一个需求&#xff1a;找到一个数所有的质因数。 初步解决 先定义一个判断质数的函数&#xff1a; def is_Prime(number):i 2count 0while i < number:if number % i 0 :count 1i 1if count > 0:return Falseelse:return True 接着定义一个寻找质…

【云原生】【k8s】Kubernetes+EFK构建日志分析安装部署

目录 EFK安装部署 一、环境准备&#xff08;所有主机&#xff09; 1、主机初始化配置 2、配置主机名并绑定hosts&#xff0c;不同主机名称不同 3、主机配置初始化 4、部署docker环境 二、部署kubernetes集群 1、组件介绍 2、配置阿里云yum源 3、安装kubelet kubeadm …

模型数据处理-数据放入 session和@ModelAttribute 实现 prepare 方法详细讲解

&#x1f600;前言 本文详细讲解了模型数据处理-数据放入 session和ModelAttribute 实现 prepare 方法详细讲解 &#x1f3e0;个人主页&#xff1a;尘觉主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是尘觉&#xff0c;希望我的文章可以帮助到大家&#xff0c…

企业数字化转型大数据湖一体化平台项目建设方案PPT

导读&#xff1a;原文《企业数字化转型大数据湖一体化平台项目建设方案PPT》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 喜欢文章&#xff0c;您可以点赞评论转发…

知识体系总结(九)设计原则、设计模式、分布式、高性能、高可用

文章目录 架构设计为什么要进行技术框架的设计 六大设计原则一、单一职责原则二、开闭原则三、依赖倒置原则四、接口分离原则五、迪米特法则&#xff08;又称最小知道原则&#xff09;六、里氏替换原则案例诠释 常见设计模式构造型单例模式工厂模式简单工厂工厂方法 生成器模式…

设计模式篇---抽象工厂(包含优化)

文章目录 概念结构实例优化 概念 抽象工厂&#xff1a;提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无须指定它们具体的类。 工厂方法是有一个类型的产品&#xff0c;也就是只有一个产品的抽象类或接口&#xff0c;而抽象工厂相对于工厂方法来说&#xff0c;是有…

Android Studio实现解析HTML获取图片URL,将URL存到list,进行列表展示

目录 效果build.gradle(app)添加的依赖(用不上的可以不加)AndroidManifest.xml错误代码activity_main.xmlitem_image.xmlMainActivityImage适配器ImageModel 接收图片URL效果 build.gradle(app)添加的依赖(用不上的可以不加) dependencies {implementation com.square…

Python可视化在量化交易中的应用(11)_Seaborn折线图

举个栗子&#xff0c;用seaborn绘制折线图。 Seaborn中折线图的绘制方法 在seaborn中&#xff0c;我们一般使用sns作为seaborn模块的别名&#xff0c;因此&#xff0c;在下文中&#xff0c;均以sns指代seaborn模块。 seaborn中绘制折线图使用的是sns.lineplot()函数&#xff…

中国剩余定理及扩展

目录 中国剩余定理解释 中国剩余定理扩展——求解模数不互质情况下的线性方程组&#xff1a; 代码实现&#xff1a; 互质&#xff1a; 非互质&#xff1a; 中国剩余定理解释 在《孙子算经》中有这样一个问题&#xff1a;“今有物不知其数&#xff0c;三三数之剩二&#x…

【C++】做一个飞机空战小游戏(十)——子弹击落炮弹、炮弹与飞机相撞

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…

Mybatis的SqlSource SqlNode BoundSql

学习链接 MyBatis SqlSource解析 【Mybatis】Mybatis源码之SqlSource#getBoundSql获取预编译SQL Mybatis中SqlSource解析流程详解 Mybatis TypeHandler解析 图解 Mybatis的SqlSource&SqlNode - processon DynamicSqlSource public class DynamicSqlSource implement…

极致鸿蒙2.0——华为MatePad系列安装AidLux,一个自带vscode的Python编译环境

看着刚刚人入手的华为鸿蒙系统MatePad11平板&#xff0c;是如此的美轮美奂&#xff0c;但是总感觉少了点什么&#xff0c;少了点什么呢&#xff1f;是编程环境&#xff0c;我爱MatePad&#xff0c;也爱编程&#xff0c;那如果可以在MatePad上编程&#xff0c;会发生什么&#x…

SpringBoot、Java 使用 Jsoup 解析 HTML 页面

使用 Jsoup 解析 HTML 页面 什么是 Jsoup&#xff1f; Jsoup 是一个用于处理 HTML 页面的 Java 库&#xff0c;它提供了简单的 API&#xff0c;使得从 HTML 中提取数据变得非常容易。无论是获取特定标签的内容还是遍历整个页面的元素&#xff0c;Jsoup 都能轻松胜任。 如何使…

【ARM Linux 系统稳定性分析入门及渐进12 -- GDB内存查看命令 “x“(examine)】

文章目录 gdb 内存查看命令 examine 上篇文章&#xff1a;ARM Linux 系统稳定性分析入门及渐进11 – GDB( print 和 p 的使用| 和 &#xff1a;&#xff1a;的使用|ptype|{&#xff1c;type&#xff1e;} &#xff1c;addr&#xff1e; ) gdb 内存查看命令 examine examine是…

c语言——判断,判断是否是字母

//判断&#xff0c;判断是否是字母 #include<stdio.h> #include<stdlib.h> int main() {char c;printf("输入字符&#xff1a;");scanf("%c",&c);if((c>a&&c<z)||(c>A&&c<Z)) //a~z的ASCLL区间是97-122&…