Linux操作系统之进程信号

进程信号

  • 一、信号
    • 1、概念
    • 2、系统定义的信号列表
    • 3、常见的信号处理方式
  • 二、产生信号的方式
    • 1、终端按键
      • (1)组合键
      • (2)示例代码
      • (3)运行结果
    • 2、调用系统函数
      • (1)kill命令
      • (2)kill函数
        • 【1】函数
        • 【2】描述
      • (3)raise函数
        • 【1】函数
        • 【2】描述
      • (4)abort函数
        • 【1】函数
        • 【2】描述
    • 3、软件条件
      • (1)alarm函数
      • (2)描述
      • (3)示例代码
      • (4)运行结果
    • 4、硬件异常
  • 三、阻塞信号
    • 1、概念
    • 2、信号在内核中的示意图
    • 3、解释
  • 四、信号集
    • 1、sigset_t
      • (1)定义
      • (2)应用
    • 2、信号集操作函数
      • (1)函数
      • (2)描述
      • (3)返回值
    • 3、sigprocmask函数
      • (1)函数
      • (2)描述
      • (3)参数how的有效值
    • 4、sigpending函数
      • (1)函数
      • (2)描述
    • 5、示例代码
  • 五、信号捕捉
    • 1、捕捉信号
      • (1)概念
      • (2)过程示意图
    • 2、signal函数
      • (1)函数
      • (2)描述
    • 3、sigaction函数
      • (1)函数
      • (2)描述
    • 4、可重入函数
      • (1)概念
  • 六、SIGCHLD信号

一、信号

1、概念

  • 在Linux中用于进程间通信和控制的一种机制,是进程之间事件异步通知的一种方式,属于软中断。
  • 所有信号的产生,最终都要由OS来进行执行,因为OS是进程的管理者。
  • 信号的处理可以不立即处理,而在合适的时候再处理。它有一个时间窗口,在这个时间窗口内,必须记住信号的到来。
  • 尽管进程没有收到信号,它也要知道对合法信号的处理操作,这属于进程内置功能的一部分。

2、系统定义的信号列表

在这里插入图片描述

  • 每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到。
  • 编号34以下的信号为普通信号,编号34及以上的信号为实时信号。
  • 信号 SIGKILL 和 SIGSTOP 无法被捕获或者忽略。

3、常见的信号处理方式

  • SIG_IGN:忽略信号。
  • SIG_DFL:执行信号的默认处理动作。
  • 捕捉信号:提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数。

二、产生信号的方式

1、终端按键

(1)组合键

  • Ctrl + c:信号2(SIGINT)。
  • Ctrl + \:信号3(SIGQUIT)。

(2)示例代码

void handler(int signo)
{cout << "get a signo: " << signo << endl;
}int main()
{for(int i = 1; i <= 31; ++i){signal(i, handler);}while(true){cout << "I am a crazy process" << " pid = " << getpid() << endl;sleep(1);}return 0;
}

(3)运行结果

在这里插入图片描述

在这里插入图片描述

2、调用系统函数

(1)kill命令

  • 命令行输入:kill -signo pid

(2)kill函数

【1】函数

在这里插入图片描述

【2】描述
  • kill函数,即系统调用,可用于向任何进程或进程组发送任何信号。
  • 如果 pid 为正数,则将 sig 信号发送到 pid 指定的进程。
  • 如果 pid 等于 0,则 sig 信号将发送到调用进程的进程组中的每个进程。
  • 如果 pid 等于 -1,则 sig 信号将发送到调用进程有权发送信号的每个进程,但进程1(init)除外。
  • 如果 pid 小于 -1,则 sig 将发送到进程组中 ID 为 -pid 的每个进程。
  • 如果 sig 为 0,则不发送信号,但仍执行错误检查。这可用于检查进程 ID 或进程组 ID 是否存在。

(3)raise函数

【1】函数

在这里插入图片描述

【2】描述
  • raise函数向调用进程或线程发送 sig 信号。
  • 在单线程程序中,它等价于 kill(getpid(), sig);
  • 在多线程程序中,它等价于 pthread_kill(pthread_self(), sig);
  • 如果信号有自定义的处理函数,则raise函数只有在该函数返回后才会返回。

(4)abort函数

【1】函数

在这里插入图片描述

【2】描述
  • abort函数首先取消 SIGABRT 信号的阻塞状态,然后为调用它的进程引发该信号。 而这会导致进程异常终止,除非 SIGABRT 信号被捕获并且信号处理程序(自定义的信号处理方法)没有返回。
  • 如果abort函数导致进程终止,则关闭并刷新所有打开的流。
  • 如果 SIGABRT 信号被忽略,或被返回的处理程序(自定义的信号处理方法)捕获,则 abort函数仍将终止进程。 它通过恢复 SIGABRT 的默认配置,然后再次引发该信号来实现此目的。

3、软件条件

(1)alarm函数

在这里插入图片描述

(2)描述

  • alarm函数安排在seconds秒后将 SIGALRM 信号传送到调用进程。
  • 如果秒数为零,则取消任何挂起的警报。
  • 在任何情况下,任何先前用alarm函数设置的“闹钟”都会被取消。
  • alarm函数的返回值为,如果没有先前安排的“闹钟”,则返回零;反之,返回距离任何先前安排的“闹钟”发出 SIGALRM 信号的剩余秒数。

(3)示例代码

void handler(int signo)
{cout << "get signo: " << signo << endl;unsigned int n = alarm(5);cout << "剩余时间:" << n << endl;
}int main()
{signal(SIGALRM, handler);alarm(50);while(true){cout << "this process pid: " << getpid() << endl;sleep(1);}return 0;
}

(4)运行结果

在这里插入图片描述
在这里插入图片描述

4、硬件异常

硬件异常被硬件以某种方式检测到并通知内核,然后内核向当前进程发送适当的信号。

三、阻塞信号

1、概念

  • 信号递达(Delivery):执行信号的处理动作。
  • 信号未决(Pending):信号从产生到递达之间的状态。
  • 信号阻塞(Block):被阻塞的信号产生时将保持在未决状态,直到进程解除对该信号的阻塞才能执行递达的动作,即只要信号被阻塞就不会递达。

2、信号在内核中的示意图

在这里插入图片描述

3、解释

  • 标志位block是信号阻塞,标志位pending是信号未决,1表示设置,0表示未设置。函数指针表handler是信号的处理方法。
  • 信号产生时,内核在进程控制块中设置该信号的未决标志(置1),直到信号递达才清除该标志(置0)。
  • 在上方的图中,SIGHUP信号产生过,但是被阻塞了,所以暂时不能递达,当它递达时执行默认处理动作;SIGINT信号未产生过且被阻塞了,当产生SIGINT信号时,该信号将会被阻塞,即pending只将该信号的位置置为1而不会递达。它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号。因为进程仍有机会改变处理动作之后再解除阻塞。SIGQUIT信号未阻塞也未产生过,它的处理动作是用户自定义函数sighandler。
  • 在Linux中,常规信号在进程解除阻塞之前如果产生过多次,则在递达之前只计一次。而实时信号如果在递达之前产生过多次可以依次放在一个队列里,即实时信号的每一次产生都有效。

四、信号集

1、sigset_t

(1)定义

在这里插入图片描述
在这里插入图片描述

(2)应用

  • 在标志位block和pending中,每个信号只有一个bit的标志,即非0即1,不会记录对应信号产生的次数。
  • sigset_t:信号集,阻塞(block)和未决(pending)标志可以用它来存储,这个类型可以表示每个信号的“有效”或“无效”状态。
  • 在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。
  • 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask)。

2、信号集操作函数

(1)函数

在这里插入图片描述

(2)描述

  • sigemptyset:将 set 给出的信号集初始化为空,即将所有的信号都从集合中排除。
  • sigfillset:将 set 初始化为 full,即将所有信号都设置在内。
  • sigaddset:添加 set 中signum对应的信号。
  • sigdelset:删除 set 中signum对应的信号。
  • sigismember:测试 signum 是否是 set 的成员,即测试 signum 是否在set 中。
  • sigset_t 类型的对象必须通过调用 sigemptyset 或 sigfillset 进行初始化,然后才能传递给函数 sigaddset、sigdelset和 sigismember;或者下面描述的其他 glibc 函数(sigisemptyset()、sigandset() 和 sigorset())。 如果不这样做,结果是未定义的。

(3)返回值

  • sigemptyset、sigfillset、sigaddset 和 sigdelset 成功时返回 0,错误时返回 -1。
  • 对于sigismember来说,如果 signum 是 set 的成员,则返回 1,如果 signum 不是 set 的成员,则返回 0,错误时返回 -1。
  • 出错时,这些函数会设置 errno 以指示原因。

3、sigprocmask函数

(1)函数

在这里插入图片描述

(2)描述

  • sigprocmask函数用于获取和/或更改调用线程的信号掩码。
  • sigprocmask函数调用的行为取决于 how 的值。
  • 如果 oldset 为非 NULL,则信号掩码的上一个值将存储在 oldset 中。
  • 如果 set 为 NULL,则信号掩码保持不变(即忽略 how),但信号掩码的当前值仍通过 oldset 返回(如果它不是 NULL)。

(3)参数how的有效值

  • SIG_BLOCK:阻塞信号集将被设置为当前信号集和参数 set 的并集,即将 set 中包含的信号都阻塞。
  • SIG_UNBLOCK:参数 set 集合中的信号将从当前受阻信号集中移除,即 set 中包含的信号将被设置为不阻塞。 允许尝试解锁未被阻塞的信号。
  • SIG_SETMASK:将阻塞信号集的内容设置为参数 set 的内容。

4、sigpending函数

(1)函数

在这里插入图片描述

(2)描述

  • sigpending函数返回等待传送到调用线程的信号集(即在被阻塞时引发的信号)。
  • 挂起信号的掩码在参数set中返回。

5、示例代码

#include<iostream>
#include<unistd.h>
#include<signal.h>
using namespace std;void PrintSignal(const sigset_t& pending)
{for(int i = 31; i >= 1; --i){if(sigismember(&pending, i))cout << "1";elsecout << "0";}cout << "\n" << endl;
}int main()
{sigset_t bset, oset;sigemptyset(&bset);sigemptyset(&oset);for(int i = 1; i <= 31; ++i){sigaddset(&bset, i);}sigprocmask(SIG_SETMASK, &bset, &oset);sigset_t pending;sigemptyset(&pending);while(true){int ret = sigpending(&pending);if(ret == -1)continue;PrintSignal(pending);sleep(1);}return 0;
}

五、信号捕捉

1、捕捉信号

(1)概念

  • 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数。
  • 当我们的进程从内核态返回到用户态的时候,进行信号的检测和处理。

(2)过程示意图

在这里插入图片描述

2、signal函数

(1)函数

在这里插入图片描述

(2)描述

  • signal函数的行为在 UNIX 版本中各不相同,在不同版本的 Linux 中也存在差异。
  • signal函数将 signum 信号的处置(处理方法)设置为处理程序handler,该处理程序是SIG_IGN、SIG_DFL或自定义函数(handler)的地址。
  • 如果 signum 信号被传送到进程,则会发生以下情况之一。如果处置(处理方法)设置为 SIG_IGN,则忽略该信号;如果处置设置为 SIG_DFL,则发生与该信号关联的默认操作;如果处置设置为自定义函数(handler),则首先将处置重置为 SIG_DFL,或者信号被阻止,然后使用参数 signum 调用处理程序(handler)。 如果调用处理程序导致信号被阻塞,则信号在从句柄(handler)返回时被解除阻塞。
  • signal函数返回值为,当调用成功时,返回信号处理程序的上一个值,失败则返回SIG_ERR,并设置errno,用来指示错误原因。

3、sigaction函数

(1)函数

在这里插入图片描述
在这里插入图片描述

(2)描述

  • sigaction系统调用用于更改进程在接收到特定信号时所采取的操作。
  • signum:指定信号,可以是除 SIGKILL 和 SIGSTOP 之外的任何有效信号。
  • 如果 act 为非 NULL,则signum信号的处理操作设置为 act 中sa_handler设定的操作。 如果 oldact 为非NULL,则signum信号的上一个处理操作保存在 oldact 中。
  • 在某些涉及联合体的体系结构中,不要同时分配(设置)给sa_handler和sa_sigaction。
  • sa_restorer:元素已过时,不应使用。 POSIX 未指定 sa_restorer 元素。
  • sa_handler:指定要与 signum 关联的操作,可以设置为SIG_DFL默认操作、SIG_IGN忽略操作或指向信号处理函数的指针,此函数接收信号编号作为其唯一参数。通过用自定义函数就可以用同一个函数处理多种信号,即它是一个回调函数,不过不是被main函数调用,而是被系统所调用。
  • sa_mask:指定在执行信号处理程序期间应阻止的信号掩码(即添加执行信号到调用信号处理程序的线程的信号掩码中),除了当前信号被自动屏蔽之外,也可以通过设置它来自动屏蔽另外一些信号。 此外,触发处理程序的信号将被阻止,除非使用 SA_NODEFER 标志。
  • 当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字。这样就保证了在处理某个信号时,如果这种信号再次产生,那么它会被阻塞到当前处理函数执行结束为止。

4、可重入函数

(1)概念

  • 如果一个函数,被重复进入的情况下,出错或者可能出错,则为不可重入函数。反之,为可重入函数。

六、SIGCHLD信号

  • 子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数。
  • 父进程自定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程。当子进程终止时会通知父进程,然后父进程在信号处理函数中调用wait相关函数清理子进程,这是解决僵尸问题的一种方法,前提是父进程不提前退出。
  • 父进程调用sigaction将SIGCHLD的处理动作设置为SIG_IGN。这样用fork函数创建出来的子进程在终止时会被自动清理掉,而不会产生僵尸进程和通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略通常是没有区别的。但这是一个特例,此方法对于Linux可用,但不保证在其它类UNIX系统上都可用。

本文到这里就结束了,如有错误或者不清楚的地方欢迎评论或者私信
创作不易,如果觉得博主写得不错,请点赞、收藏加关注支持一下💕💕💕

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

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

相关文章

CRC16循环冗余校验

代码&#xff1a; #include<stdio.h> #include <stdint.h>#define uchar unsigned char #define uint unsigned int static const uint8_t auchCRCHi[] { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x0…

深入理解接口测试:实用指南与最佳实践(三)API文档解析及编写测试用例

​ ​ 您好&#xff0c;我是程序员小羊&#xff01; 前言 这一阶段是接口测试的学习&#xff0c;我们接下来的讲解都是使用Postman这款工具&#xff0c;当然呢Postman是现在一款非常流行的接口调试工具&#xff0c;它使用简单&#xff0c;而且功能也很强大。不仅测试人员会使用…

pxe自动安装linux

实验环境 1.rhel7主机 2开启主机图形&#xff08;本人最小化安装&#xff0c;先下载&#xff09; 3配置网络 4关闭VMware dhcp功能 5能够自动安装系统 完成rhedhat7图形,kickstart,启动图形化制作工具 安装kickstart 启动图形化制作工具 在ks.cfg可以添加安装时下载的包 …

算法学习day29

一、乘法表中第k小的数(和有序矩阵中第k小的数类似) 题意&#xff1a; 乘法表是大小为 m x n 的一个整数矩阵&#xff0c;其中 mat[i][j] i * j&#xff08;下标从 1 开始&#xff09;。 给你三个整数 m、n 和 k&#xff0c;请你在大小为 m x n 的乘法表中&#xff0c;找出…

可视化图表与源代码显示的动态调整

可视化图表与源代码显示的动态调整 页面效果描述&#xff1a;本篇代码实现了通过拖动一个可调整大小的分隔符&#xff0c;用户可以动态地调整图表显示区域和源代码显示区域的大小。通过监听鼠标事件&#xff0c;当用户拖动分隔符时&#xff0c;会动态计算并更新两个区域的大小 …

Vue项目学习(1)

1、进入cmd命令行——> vue ui ——>等等操作 2、 3、src目录下 4、vue项目的启动 &#xff08;1&#xff09; &#xff08;2&#xff09; 5、如何更改前端vue项目的端口号&#xff1f;——>去vue.config.js里配置应一个对象

mprpc框架的应用示例

一、注册 有一个本地服务&#xff0c;我想把它发布成远程服务&#xff0c;首先在user.proto中定义rpc方法的描述&#xff0c;定义参数和响应的消息类型 然后在userservice.cc文件中通过继承UserServiceRpc这个类&#xff0c;重写一下响应的方法&#xff08;打四个动作&#xf…

shell函数的基本知识

文章目录 shell函数定义函数调用函数函数参数返回值 Shell 输入/输出重定向输入重定向输出重定向 Shell 函数是 Shell 脚本编程中的一个非常有用的特性&#xff0c;它允许你将一段代码封装起来&#xff0c;给它一个名字&#xff08;函数名&#xff09;&#xff0c;然后在脚本的…

低代码: 开发难点分析,核心技术架构设计

开发难点分析 1 &#xff09;怎样实现组件 核心问题&#xff1a;编辑器 和 页面其实整个就是一系列元素构成的这些元素的自然应该抽象成组件&#xff0c;这些组件的属性应该怎样设计在不同的项目中怎样做到统一的使用 2 &#xff09;跨项目使用 在不同的项目中怎样做到统一的…

【Linux】线程互斥

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 如果文章对…

C# Unity 面向对象补全计划 七大原则 之 依赖倒置原则 (DIP)难度:☆☆ 总结:多抽象,多接口,少耦合

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 本系列作为七大原则和设计模式的进阶知识&#xff0c;看不懂没关系 请看专栏&#xff1a;http://t.csdnimg.cn/mIitr&#xff0c;查漏补缺 1.依赖倒置原则 (DIP) 这…

「队列」实现FIFO队列(先进先出队列|queue)的功能 / 手撕数据结构(C++)

概述 队列&#xff0c;是一种基本的数据结构&#xff0c;也是一种数据适配器。它在底层上以链表方法实现。 队列的显著特点是他的添加元素与删除元素操作&#xff1a;先加入的元素总是被先弹出。 一个队列应该应该是这样的&#xff1a; --------------QUEUE-------------——…

骨传导耳机哪个牌子好?五款业界高性能机型推荐,让你选购不迷茫!

骨传导耳机哪个牌子好&#xff1f;哪款耳机值得入手&#xff1f;作为一名资深的数码设备测评师&#xff0c;我极力推荐大家尝试下骨传导耳机&#xff0c;它无需直接堵塞耳道&#xff0c;既能起到保护听力的作用&#xff0c;又能在使用中保持对外界的环境感知。然而&#xff0c;…

OD C卷 - 园区参观路径

园区参观路径&#xff08;100&#xff09; 有一个矩形园区&#xff0c;从左上角走到右下角&#xff0c;只能向右、向下走&#xff1b;共有多少条不同的参观路径&#xff1b; 输入描述&#xff1a; 第一行输入长度、宽度 后续每一行表示 对应位置是否可以参观&#xff0c;0可…

poetry配置镜像

1.简介 poetry 是一个包管理和打包的工具。 在 Python 中&#xff0c;对于初学者来说&#xff0c;打包系统和依赖管理是非常复杂和难懂的。即使对于经验丰富的开发者&#xff0c;一个项目总是要同时创建多个文件&#xff1a; setup.py ,requirements.txt,setup.cfg , MANIFES…

【数据结构与算法】十大经典排序算法深度解析:冒泡排序、选择排序、插入排序、归并排序、快速排序、希尔排序、堆排序、计数排序、桶排序、基数排序

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​ 目录 引言 一、排序算法概述 排序算法简介 排序算法的分类 性能指标 二、十大排序算法…

Unity Rigidbody 踩坑记录

1&#xff1a;两个带有刚体的物体碰撞会一直不停的弹 把被动受力的刚提的 Freeze Position 的勾选 去掉&#xff08;碰到过一次&#xff0c;有一种受力无法释放又返回给目标的 所以一直弹跳的感觉&#xff09; 2&#xff1a;子物体 和父物体 都有刚体的情况下 子物体 Freeze R…

zdpy+vue3+onlyoffice文档系统实战上课笔记 20240805

上次 上次计划 1、最近文档表格完善 2、实现登录功能 3、新建文件&#xff0c;复制文件&#xff0c;删除文件 4、其他 目前任务&#xff1a;最近文档表格完善 1、在名称前面&#xff0c;渲染这个文档的图标 2、大小的基本的单位是kb&#xff0c;超过1024kb则换成mb&#xff0…

Java | Leetcode Java题解之第318题最大单词长度乘积

题目&#xff1a; 题解&#xff1a; class Solution {public int maxProduct(String[] words) {Map<Integer, Integer> map new HashMap<Integer, Integer>();int length words.length;for (int i 0; i < length; i) {int mask 0;String word words[i];in…

Mysql中事务的读一致性问题,以及如何用MVCC解决

事务四大特性的实现&#xff1a; 原子性事务具有回滚的能力&#xff0c;InnoDB引擎使用undo log日志表来进行回滚操作。 持久性InnoDB引擎使用redo log日志表来保证数据的持久性。 事务的隔离性产生的问题&#xff1a; 脏读&#xff1a;一个事务读取到了另一个事务未提交的数…