Linux进程通信——信号(一)

原理

对于 Linux来说,实际信号是软中断,许多重要的程序都需要处理信号。
信号,为 Linux 提供了一种处理异步事件的方法。比如,终端用户输入了ctrl+c来中断程序,会通过信号机制停止一个程序。

概述

信号的名字和编号

每个信号都有一个名字和编号,这些名字都以“SIG”开头,例如“SIGUP(挂起) ”、“SIGINT(中断)、SIGQUIT(退出)”等等。
信号定义在signal.h头文件中,信号名都定义为正整数
具体的信号名称可以 使用kill -l查看信号的名字以及序号
信号是从1开始编号的,不存在0号信号。kill对于信号0有特殊的应用。

信号的处理

信号的处理方式有三种,分别是忽略、捕捉和默认动作

忽略信号

大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是 SIGKILLSIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程,显然是内核设计者不希望看到的场景。

系统自带的忽略宏函数

 signal(SIGINT,SIG_IGN);//将SIGINT信号(ctrl+C、2)忽略

捕捉信号

需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。( 在main函数外定义一个函数,用signal函数中的参数调用该函数并执行函数中的功能)

系统默认动作

对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。
具体的信号默认动作可以使用man 7 signal来查看系统的具体定义。在此,我就不详细展开了,需要查看的,可以自行查看。也可以参考 《UNIX 环境高级编程(第三部)》的 P251——P256中间对于每个信号有详细的说明。

例子如下:

其实对于常用的 kill 命令就是一个发送信号的工具,kill 9 PID 来杀死进程。比如,我在后台运行了一个 a.out 工具,通过 ps 命令可以查看他的 PID,通过 kill 9来发送了一个终止进程的信号来结束了 a.out 进程。如果查看信号编号和名称,可以发现9对应的是 SIGKILL,正是杀死该进程的信号。而以下的执行过程实际也就是执行了9号信号的默认动作——杀死进程。

kill -9 进程PID
kill -SIGKILL 进程PID

可见,两者的执行结果相同。说明kill命令是发送信号的工具

signal函数

功能

设置某一信号的对应动作

头文件

#include <signal.h>

原型

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

函数解读

第一行是真实处理信号的函数:中断函数的原型中,有一个参数是 int 类型,显然也是信号产生的类型,方便使用一个函数来处理多个信号,即注册函数的第二个参数可以调用信号处理函数并执行其中的功能。

第二行是信号处理注册的函数:

signum信号的编号,如SIGKILL的编号是9
handler中断函数的指针,写入后可以调用编写的真实处理信号函数并执行功能

signal()会依参数signum指定的信号编号来设置该信号的处理函数。当指定的信号到达时就会跳转到参数handler指定的函数执行

返回值

成功则返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)。

代码示例

信号处理函数的注册

signal1.c

#include <stdio.h>
#include <signal.h>void handler(int signum)
{printf("get signum is %d\n",signum);printf("not quit\n");switch(signum){case 2:printf("SIGINT\n");break;case 9:printf("SIGKILL\n");break;case 10:printf("SIGUSR1\n");break;}
}int main()
{signal(SIGINT,handler);signal(SIGUSR1,handler);while(1);return 0;
}

代码编译后查看运行a.out工具,通过ps查看其编号

运用kill指令分别对信号进行处理

注:第一种按下crtl+c执行结果相同。

可见调用signal函数后匹配的正确编号后会执行handler中的功能(将函数编号打印出来)。第三个与前两个结果不一样是因为SIGKILL指令无法被忽略,这里的kill -9发出的是指令,由于代码为死循环,若SIGKILL被忽视,则会导致代码无法终止循环,所以一旦SIGKILL指令发出,程序立刻停止(被杀死)。

发送信号处理函数

signal2.c

#include <stdio.h>
#include <signal.h>int main(int argc,char **argv)//由于需要此代码发送指令另一部分代码才会执行,所以需要进行传参,参数为kill参数,格式为./a.out pid signum
{int signum;int pid;signum = atoi(argv[1]);pid = atoi(argv[2]);kill(pid,signum);//调用kill函数,将信号处理编号和工具的pid值输入即可printf("send signal success\n");return 0;
}

 先编译signal1.c(上一模块的代码)并运行

调用ps指令查看该程序的信号值

编译运行signal2.c中的代码传参即可运行signal1.c代码中的功能

将signum与pid输入后即可实现signal1.c中的功能,实现信号捕捉处理。

功能与signal2.c一样的代码:

#include <stdio.h>
#include <signal.h>int main(int argc,char **argv)
{int signum;int pid;char cmd[128] = {0};signum = atoi(argv[1]);pid = atoi(argv[2]);sprintf(cmd,"kill -%d %d",pid,signum);//cmd的指令格式为“”里的格式,即调用kill指令system(cmd);//调用cmd指令printf("send signal success\n");return 0;
}

注:
1、atoi (表示 ascii to integer)是把字符串转换成整型数的一个函数
2、sprintf指的是字符串格式化命令,函数原型为

 int sprintf(char *string, char *format [,argument,…]);

主要功能是把格式化的数据写入某个字符串中,即发送格式化输出到 string 所指向的字符串

信号忽略函数的补充

代码展示

#include<stdio.h>
#include <signal.h>
void handler(int signum)
{printf("get signum=%d\n",signum);switch(signum){case 2:printf("SIGINT\n");break;case 10:printf("SIGUSR1\n");break;}
}
int main()
{signal(SIGINT,SIG_IGN);//将SIGINT信号(ctrl+C、2)忽略signal(SIGUSR1,SIG_IGN);//将SIGUSR1信号(10)忽略while(1);return 0;
}

可见crtl+c和kill -10和kill -2都被忽略了,只有kill -9才能使该程序终止,印证的信号处理中的忽略部分不能忽略SIGKILL。

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

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

相关文章

【Docker】从零开始:8.Docker命令:Commit提交命令

【Docker】从零开始&#xff1a;8.Docker命令:Commit命令 基本概念镜像镜像分层什么是镜像分层为什么 Docker 镜像要采用这种分层结构 本章要点commit 命令命令格式docker commit 操作参数实例演示1.下载一个新的ubuntu镜像2.运行容器3.查看并安装vim4.退出容器5提交自己的镜像…

【数据结构/C++】线性表_双链表基本操作

#include <iostream> using namespace std; typedef int ElemType; // 3. 双链表 typedef struct DNode {ElemType data;struct DNode *prior, *next; } DNode, *DLinkList; // 初始化带头结点 bool InitDNodeList(DLinkList &L) {L (DNode *)malloc(sizeof(DNode))…

成为AI产品经理——模型评估概述

目录 一、模型宣讲和评估的原因 二、模型宣讲 三、模型评估 1. 重要特征 ① 特征来源 ②特征意义 2.选择测试样本 3.模型性能和稳定性 一、模型宣讲和评估的原因 刘海丰老师提到他们在做一个金融AI产品未注重模型指标&#xff0c;过于注重业务指标&#xff0c;导致产生…

解决:ImportError: cannot import name ‘Adam‘ from ‘keras.optimizers‘

解决&#xff1a;ImportError: cannot import name ‘Adam‘ from ‘keras.optimizers‘ 背景 在使用之前的代码时&#xff0c;报错&#xff1a; from keras.optimizers import Adam ImportError: cannot import name ‘Adam’ 报错问题 from keras.optimizers import Adam I…

【Java 进阶篇】Redis持久化之RDB:数据的安全守护者

Redis&#xff0c;作为一款高性能的键值存储系统&#xff0c;支持多种持久化方式&#xff0c;其中RDB&#xff08;Redis DataBase&#xff09;是其最常用的一种。RDB可以将当前时刻的数据快照保存到磁盘&#xff0c;以便在Redis重启时快速恢复数据。本文将深入探讨RDB的原理、配…

飞书智能伙伴之 AI 数智参谋:先进团队,北极星指标也要遥遥领先

11 月 22 日&#xff0c;飞书在 2023 秋季飞书未来无限大会上正式发布了飞书智能伙伴。作为首批生态伙伴&#xff0c;基于 Kyligence 智能一站式指标平台实现的 AI 数智参谋也正式亮相。这是继 11 月 21 日 Kyligence 产品发布会后&#xff0c;Kyligence 在数据驱动决策智能领域…

第十五届蓝桥杯(Web 应用开发)模拟赛 1 期-大学组(详细分析解答)

目录 1.动态的Tab栏 1.1 题目要求 1.2 题目分析 1.3 源代码 2.地球环游 2.1 题目要求 2.2 题目分析 2.3 源代码 3.迷惑的this 3.1 题目要求 3.2 题目分析 3.3 源代码 4.魔法失灵了 4.1 题目要求 4.2 题目分析 4.3 源代码 5.燃烧你的卡路里 5.1 题目要求 5.2…

第十七章:数据库操作

数据库基础 SQL语言 1、select 语句 select 语句用于从数据中检索数据。语法如下&#xff1a; SELECT 搜选字段列表 FROM 数据表名 WHERE 条件表达式 GROUP BY 字段名 HAVING 条件表达式(指定分组的条件) ORDER BY 字段名[ASC|DESC] 2、insert 语句 insert 语句用于向表中插入…

【UE5】五大基类及其使用

UObject UObject表示对象&#xff0c;准确来说&#xff0c;虚幻引擎中的对象基础类为UObject UObject提供了以下功能&#xff1a; 垃圾收集&#xff08;Garbage collection&#xff09;引用自动更新&#xff08;Reference updating&#xff09;反射&#xff08;Reflection&am…

计算机基础知识57

前后端数据传输的编码格式(contentType) # 我们只研究post请求方式的编码格式&#xff1a; get请求方式没有编码格式-- index?useranme&password get请求方式没有请求体&#xff0c;参数直接在url地址的后面拼接着 # 有哪些方式可以提交post请求&#xff1a;f…

构建个性化预约服务:预约上门服务系统源码解读与实战

随着社会的发展&#xff0c;预约上门服务系统在满足用户需求、提升服务效率方面发挥着越来越重要的作用。在本文中&#xff0c;我们将深入研究预约上门服务系统的源码&#xff0c;通过实际的技术代码示例&#xff0c;揭示系统内部的关键机制&#xff0c;以及如何在实际项目中应…

深入了解接口测试:方法、工具和关键考虑因素(一)

接口测试是软件测试中的一项重要工作&#xff0c;它涉及到系统与系统之间的交互点。接口可以是外部接口&#xff0c;也可以是内部接口&#xff0c;包括上层服务与下层服务接口以及同级接口。在接口测试中&#xff0c;我们需要确保接口能够按照预期的方式进行通信和交互&#xf…

【攻防世界-misc】can_has_stdio?

1.用记事本打开文件是这样子的&#xff0c; 这是一段BF&#xff08;Brainfuck&#xff09;编程语言代码&#xff0c;属于一种极简化的编程语言&#xff0c;用于演示计算机程序设计概念。这段代码包含了一些操作符&#xff0c;如">"表示指针向右移动&#xff0c;&q…

【C++破局】泛型编程|函数模板|类模板

​作者主页 &#x1f4da;lovewold少个r博客主页 ⚠️本文重点&#xff1a;c模板初阶知识点讲解 &#x1f449;【C-C入门系列专栏】&#xff1a;博客文章专栏传送门 &#x1f604;每日一言&#xff1a;花有重开日&#xff0c;人无再少年 目录 前言 泛型编程 函数模板 函数模…

用Java实现简易的图书管理系统(超详细)

目录 1.设计背景 2.设计思路 3.模块展示及代码演示 3.1 Book类的实现 3.2 BookList类的实现(书架) 3.3 异常类的实现(OperationException) 3.4 用户类的实现 3.5 操作接口的实现(定义规范) 3.6 操作类的具体实现 3.6.1 增加操作 3.6.2 查找操作 3.6.3 删除操作 3.6…

标签打印机打印标签时出现,数据处理过程中错误 无法设置项目 图片1的内容无法打印

环境&#xff1a; Win10专业版 NiceLabel Designer 10.1 问题描述&#xff1a; 标签打印机打印标签时出现&#xff0c;数据处理过程中错误 无法设置项目 图片1的内容无法打印 解决方案&#xff1a; 1.删除标签部分文字打印测试 还是一样&#xff08;未解决&#xff09; …

jenkins 参数构建

应用保存 [rootjenkins-node1 .ssh]# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved i…

【嵌入式面试】2022年嵌入式经典面试题汇总(C语言)

&#x1f4dc;作者&#xff1a;不想脱发的基兄 &#x1f4fa;专栏&#xff1a;《嵌入式面试》 &#x1f4e3;格言&#xff1a;不管前方的路有多苦&#xff0c;只要走的方向正确&#xff0c;不管多么崎岖不平&#xff0c;都比站在原地更接近幸福。 前言&#xff1a; 2022年秋招我…

C++之初始化列表详细剖析

一、初始化列表定义 初始化列表&#xff1a;以一个冒号开始&#xff0c;接着是一个以逗号分隔的数据成员列表&#xff0c;每个"成员变量"后面跟一个放在括号中的初始值或表达式。 class Date { public:Date(int year, int month, int day): _year(year), _month(mont…

OpenCV快速入门:图像分析——图像分割和图像修复

文章目录 前言一、图像分割1.1 漫水填充法1.1.1 漫水填充法原理1.1.2 漫水填充法实现步骤1.1.3 代码实现 1.2 分水岭法1.2.1 分水岭法原理1.2.2 分水岭法实现步骤1.2.3 代码实现 1.3 GrabCut法1.3.1 GrabCut法原理1.3.2 GrabCut法实现步骤1.3.3 代码实现 1.4 Mean-Shift法1.4.1…