信号

信号也是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.mfbz.cn/a/81774.html

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

相关文章

回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现SA-SVM模拟退火算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本…

Scratch 之 RPG 引擎制作教程(1) / 地图行走

大家好&#xff0c;又和大家见面了&#xff0c;那么我们这期讲的就是RPG游戏的地图以及人物的行走。 我发现大家并不是很懂RPG游戏引擎&#xff0c;也就是说这种引擎对于技术的要求还是比较高的。为了让更多人直接上手制作RPG游戏&#xff0c;我打算开启这一系列教程。 这个教程…

Azure应用程序网关

文章目录 什么是应用程序网关实战演练创建虚拟网络创建虚拟机创建应用程序网关测试搭建结果 什么是应用程序网关 Azure应用程序网关是一种托管服务&#xff0c;用于提供安全、可缩放的 Web 应用程序前端点的应用程序传送控制和保护。它可以通过 SSL 终止、cookie 基于会话持久…

Cesium加载Supermap的wmts服务

最近使用cesium 加载supermap的wmts 服务&#xff0c;多次遇到加载异常与白页面问题&#xff0c;纠结好久最后才搞定[特此记录] 1、首先找到方法加载wmts 的api 文档 官方提示使用WebMapTileServiceImageryProvider加载wmts 2、然后编辑加载代码 //1.新建ImageryProviderlet…

【rust/egui】(三)看看template的app.rs:序列化、持久化存储

说在前面 rust新手&#xff0c;egui没啥找到啥教程&#xff0c;这里自己记录下学习过程环境&#xff1a;windows11 22H2rust版本&#xff1a;rustc 1.71.1egui版本&#xff1a;0.22.0eframe版本&#xff1a;0.22.0上一篇&#xff1a;这里 serde app.rs中首先定义了我们的Templ…

Three.js程序化3D城市建模【OpenStreetMap】

对于我在 Howest 的研究项目&#xff0c;我决定构建一个 3D 版本的 Lucas Bebber 的“交互式讲故事的动画地图路径”项目。 我将使用 OSM 中的矢量轮廓来挤出建筑物的形状并将它们添加到 3js 场景中&#xff0c;随后我将对其进行动画处理 推荐&#xff1a;用 NSDT编辑器 快速搭…

ARM-M0内核MCU,内置24bit ADC,采样率4KSPS,传感器、电子秤、体脂秤专用,国产IC

ARM-M0内核MCU 内置24bit ADC &#xff0c;采样率4KSPS flash 64KB&#xff0c;SRAM 32KB 适用于传感器&#xff0c;电子秤&#xff0c;体脂秤等等

08 - 网络通信优化之IO模型:如何解决高并发下IO瓶颈?

提到 Java I/O&#xff0c;相信你一定不陌生。你可能使用 I/O 操作读写文件&#xff0c;也可能使用它实现 Socket 的信息传输…这些都是我们在系统中最常遇到的和 I/O 有关的操作。 我们都知道&#xff0c;I/O 的速度要比内存速度慢&#xff0c;尤其是在现在这个大数据时代背景…

postgresql 的递归查询

postgresql 的递归查询功能很强大&#xff0c;可以实现传统 sql 无法实现的事情。那递归查询的执行逻辑是什么呢&#xff1f;在递归查询中&#xff0c;我们一般会用到 union 或者 union all&#xff0c;他们两者之间的区别是什么呢&#xff1f; 递归查询的执行逻辑 递归查询的…

leetcode中常用的 C++函数和 STL容器

C函数和 STL容器 输入输出C排序sortC翻转字符串reverseC截取字符串strsub哈希表的使用定义查询哈希表里是否有该key在哈希表里存放键值链式哈希 哈希集合定义一个哈希集合查找一个字符是否在set里面删除和添加 优先队列 最大堆优先队列的大顶堆定义方式插入存储数组对定义插入 …

idea使用docker生成镜像(打包镜像,导入镜像,导出镜像)

1&#xff1a;先下载安装dockerdesktop&#xff0c;安装成功后 2&#xff1a; 在cmd执行docker -v&#xff0c;查看安装的docker版本 C:\Users\dell>docker -v Docker version 24.0.5, build ced09963&#xff1a;需要启动 dockerdesktop应用&#xff0c;才算启动docker&a…

⛳ TCP 协议详解

目录 ⛳ TCP 协议详解&#x1f3a8; 一、TCP / IP 协议的分层模型&#x1f3d3; 1.1、应用层&#x1f9f8; 1.2、传输层&#x1f52e; 1.3、网络层&#x1f3af; 1.4、链路层 &#x1f3ed; 二、HTTP 报文传输原理&#x1f945; 2.1、HTTP 报文传输&#x1f48e; 2.2、封装和分…

计算机网络-物理层(三)编码与调制

计算机网络-物理层&#xff08;三&#xff09;编码与调制 在计算机网络中&#xff0c;计算机需要处理和传输用户的文字、图片、音频和视频&#xff0c;它们可以统称为消息 数据是运输信息的实体&#xff0c;计算机只能处理二进制数据&#xff0c;也就是比特0和比特1。计算机中…

aardio开发语言Excel数据表读取修改保存实例练习

import win.ui; /*DSG{{*/ var winform win.form(text"aardio form";right759;bottom479) winform.add( buttonEnd{cls"button";text"末页";left572;top442;right643;bottom473;z6}; buttonExcelRead{cls"button";text"读取Exce…

用 VB.net,VBA 两种方式 读取单元格内的 换行数据,并出力到 CSV文件

用 VB.net&#xff0c;VBA 两种方式 读取单元格内的 换行数据&#xff0c;并出力到 CSV文件 需求 如下图所示&#xff0c;为了生成csv文件导入数据库&#xff0c;需要将下图 的 1 和 2 拼接成 如下 3 所示的一行数据&#xff0c; 开头为 1 &#xff0c;往后为 2 的换行数据 将换…

中国大学生服务外包创新创业大赛丨借 AI 之力,助“记账”难题

一、中国大学生服务外包创新创业大赛 赛事介绍 中国大学生服务外包创新创业大赛&#xff0c;是响应国家关于鼓励服务外包产业发展、加强服务外包人才培养的相关战略举措与号召&#xff0c;举办的每年一届的全国性竞赛。 大赛均由中华人民共和国教育部、中华人民共和国商务部…

selenium 选定ul-li下拉选项中某个指定选项

场景&#xff1a;selenium的下拉选项是ul-li模式&#xff0c;选定某个指定的选项。 from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 显示等待def select_li(self, text, *ul_locator):"…

对话音视频牛哥:开发RTSP|RTMP直播播放器难不难?难在哪?

我关注的播放器指标 好多开发者跟我交流音视频相关技术的时候&#xff0c;经常问我的问题是&#xff0c;多久可以开发个商业级别的RTMP或RTSP播放器&#xff1f;你们是怎样做到毫秒级延迟的&#xff1f;为什么一个播放器&#xff0c;会被你们做到那么复杂&#xff1f;带着这些…

Mac 使用 rar 命令行工具解压和压缩文件

在 Mac 中常遇到的压缩文件有 zip 和 rar 格式的&#xff0c;如果是 zip 格式的 Mac 系统默认双击一下文件就能直接解压了&#xff0c;但 rar 文件就不行。 需要额外下载 rar 工具了实现。 第一步&#xff1a;下载 rar 工具 工具网址&#xff1a;https://www.rarlab.com/dow…

Visual Studio 2022连接远程系统进行C/C++开发

Visual Studio被称为是宇宙最强IDE&#xff0c;以前开发Linux C/C服务器程序&#xff0c;基本上都是在Windows上使用VS编写跨平台的C/C代码&#xff0c;然后先在VS中编译、链接、调试&#xff0c;然后在Linux下编译、链接&#xff0c;再针对Linux下的特定代码进行调试。后面Vis…
最新文章