信号

news2024/9/20 9:43:18

信号也是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,再执行kill
	kill(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.coloradmin.cn/o/897957.html

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

相关文章

【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPushConsumer的实现原理及源码分析

RocketMQ开源是使用文件作为持久化工具&#xff0c;阿里内部未开源的性能会更高&#xff0c;使用oceanBase作为持久化工具。 在RocketMQ1.x和2.x使用zookeeper管理集群&#xff0c;3.x开始使用nameserver代替zk&#xff0c;更轻量级&#xff0c;此外RocketMQ的客户端拥有两种的…

【快应用】图片放大预览功能的实现

【关键词】 放大、image、background-position 【问题背景】 快应用中并没有直接的放大图片预览的功能&#xff0c;然而是可以利用现有的功能去实现图片的放大预览功能的。这样在快应用中浏览页面内容遇到图片时&#xff0c;遇到一些小图&#xff0c;觉得图片内容是不错的&am…

基于Three.js的WebXR渲染入门

1、Three.js 渲染管线快速概览 我不会花太多时间讨论 Three.JS 渲染管道的工作原理,因为它在互联网上有详细记录(例如,此链接)。 我将在下图中列出基础知识,以便更容易理解各个部分的去向。 2、WebXR 设备 API 入门 在我们深入了解 WebXR API 本身之前,您应该知道 WebX…

Linux如何改变文件的权限

Linux如何改变文件的权限 权限介绍权限更改关键字chmod通过数字修改通过字母修改 权限介绍 文件类型和文件权限由10个字符组成 文件的类型&#xff1a;- 表示文件&#xff0c; d 表示文件夹文件权限&#xff1a;r 表示读权限&#xff0c;w 表示写权限&#xff0c;x 表示执行权…

vue浏览器插件安装-各种问题

方法1&#xff1a;vue.js devtolls插件下载 https://blog.csdn.net/qq_55640378/article/details/131553642 下载地址&#xff1a; Tags vuejs/devtools GitHub npm install 或是 cnpm install 遇到的报错 设置淘宝镜像源&#xff08;推荐使用nrm&#xff0c;这一步是为…

219、仿真-基于51单片机L298直流电机开始停止正反转加减速Proteus仿真设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&a…

韦东山-电子量产工具项目:UI系统

代码结构 所有代码都已通过测试跑通&#xff0c;其中代码结构如下&#xff1a; 一、include文件夹 1.1 common.h #ifndef _COMMON_H #define _COMMON_Htypedef struct Region {int iLeftUpX; //区域左上方的坐标int iLeftUpY; //区域左下方的坐标int iWidth; //区域宽度…

英雄大战反派 Game Jam

围绕英雄与反派之间的冲突&#xff0c;制作惊心动魄的游戏。 所有游戏创作者和梦想家请注意&#xff01;准备释放您的创造力&#xff0c;进入一个充满冲突和传奇战役的世界。我们很高兴为您带来《英雄大战反派》终极 Game Jam&#xff0c;仅限使用 The Sandbox 的 Game Maker 进…

SVD奇异值分解相关技术

重要说明&#xff1a;本文从网上资料整理而来&#xff0c;仅记录博主学习相关知识点的过程&#xff0c;侵删。 一、参考资料 Eigen 矩阵的SVD分解 奇异值分解&#xff08;SVD&#xff09; 二、相关介绍 1. 单位阵 主对角线全为1的方阵&#xff0c;称为单位阵&#xff0c;…

unity 之 GetComponent 获取游戏对象上组件实例方法

GetComponent 简单介绍 GetComponent 是Unity引擎中用于获取游戏对象上组件实例的方法。它允许您从游戏对象中获取特定类型的组件&#xff0c;以便在脚本中进行操作和交互。 GetComponent< ComponentType >(): 这是一个泛型方法&#xff0c;用于从当前游戏对象上获取指定…

解锁数据中心高效监测精密空调,现学现用!

精密空调监控在当今科技发展中扮演着至关重要的角色。无论是数据中心、实验室还是医疗设施&#xff0c;都需要维持恒定的温度、湿度和空气质量&#xff0c;以确保设备的正常运行和数据的准确性。 精密空调监控不仅是现代高科技环境中的必备工具&#xff0c;也是保障设备稳定性、…

idea 本地版本控制 local history

idea 本地版本控制 local history 如何打开 1 自定义快捷键 settings->keymap->搜索框输入 show history -》Add Keyboard Shortcut -》设置为 CtrlAltL 2 右键文件-》local history -》show history 新建文件 版本1&#xff0c;creating class com.geekmice…这个是初…

同一个局域网主机中的一台主机连接另一台主机的虚拟机

星光下的赶路人star的个人主页 理想的路总是为有信心的人预备着 文章目录 1、描述问题2、解决前提3、解决办法4、实操4.1 虚拟机配置4.2 主机防火墙配置&#xff08;是你要连接虚拟机的所在的主机&#xff09;4.3 连接测试 1、描述问题 想要连接朋友主机的虚拟机&#xff0c;利…

光电效应波粒二象性

光电效应&#xff1a;光照射在金属表面时&#xff0c;瞬间&#xff08;t &#xff1c;10^-9s&#xff09;释放出电子的现象。 光电效应规律&#xff1a; 1、任何一种金属都有一个截止频率&#xff0c;低于该截止频率不能发生光电效应&#xff1b; 2、光电子最大初动能与入射光的…

“我30岁了,转行IT行业!还有没有出路?”

人到30&#xff0c;就容易产生中年危机。俗话说30而立&#xff0c;但其实很不容易&#xff0c;成家不易、立业也不易&#xff0c;尤其是现如今房价这么贵&#xff0c;物价那么高&#xff0c;各种压力随之而来。在职场中工作了几年&#xff0c;到近30岁时如果还是没有太大进展&a…

vue2+vue3封装使用svg图标

需求&#xff1a;1.在vue2中封装使用svg 2.在vue3中封装使用svg 3.在vue3中使用自定义插件封装多个组件 1.获取svg图标操作 在阿里巴巴矢量图标库找自己需要的svg图标 地址&#xff1a;阿里巴巴矢量图标库 随便找个图标点击下载 选择好尺寸后就可以点击复制svg代码了 在ass…

基于互斥锁的生产者消费者模型

文章目录 生产者消费者 定义代码实现 / 思路完整代码执行逻辑 / 思路 局部具体分析model.ccfunc&#xff08;消费者线程&#xff09; 执行结果 生产者消费者 定义 生产者消费者模型 是一种常用的 并发编程模型 &#xff0c;用于解决多线程或多进程环境下的协作问题。该模型包含…

Windows如何部署Jenkins

一、简介 Jenkins 是国际上流行的免费开源软件项目&#xff0c;基于Java 开发持续集成工具&#xff0c;用于监控持续重复的工作&#xff0c;提供一个开放的易用的软件平台&#xff0c;使软件的持续集成自动化&#xff0c;大大节约人力和时效。 二、Java JDK 访问 OpenLogic…

入行嵌入式的几个必备技能

嵌入式作为时下最热的行业之一&#xff0c;有不少朋友想入行却不得其法&#xff0c;这里为大家提供几个嵌入式行业必备的技能。 精通C语言 嵌入式系统中&#xff0c;精通C语言至关重要。 对于嵌入式软件开发者而言&#xff0c;掌握C语言是必要条件。在大学期间&#xff0c;你…

【8月19日】红帽openstack管理课程(CL210) 新一轮开课

课程介绍 通过实验室操作练习&#xff0c;学员将能够深入学习红帽企业 Linux OpenStack 平台各服务的手动安装方法&#xff0c;还将了解 OpenStack 开发社区的未来发展计划。 培训地点&#xff1a; 线下面授&#xff1a;苏州市姑苏区干将东路666号和基广场401室&#xff1b;…