【Linux】信号-下

在这里插入图片描述

欢迎来到Cefler的博客😁
🕌博客主页:折纸花满衣
🏠个人专栏:题目解析
🌎推荐文章:【LeetCode】winter vacation training

在这里插入图片描述


目录

  • 👉🏻信号递达,信号未决,信号阻塞
    • block表 ,pending表 ,handler表
    • sigset_t类型
  • 👉🏻信号集操作函数
    • 常见信号集操作函数
    • sigaction函数
    • sigprocmask函数
    • sigpending函数

👉🏻信号递达,信号未决,信号阻塞

在操作系统中,进程之间可以通过信号进行通信。当一个进程向另一个进程发送信号时,会出现以下几种情况:信号递达、信号未决和信号阻塞。

  1. 信号递达(Signal Delivery):当一个进程向目标进程发送信号时,操作系统会将该信号递送给目标进程。递达的信号会触发目标进程相应的信号处理函数(signal handler)执行,或者引起默认的信号处理行为。这意味着信号已经成功传递到了目标进程。

  2. 信号未决(Signal Pending):如果目标进程正在处理一个信号,而此时又有一个相同的信号递达给它,那么这个信号就会被标记为未决状态。未决信号是一种被记录下来但尚未被处理的信号

  3. 信号阻塞(Signal Blocking):进程可以选择性地阻塞某些信号,使得它们在阻塞状态下不会递达到该进程。当信号被阻塞时,即使有该信号的递达请求,进程也不会接收到该信号。当解除对信号的阻塞时,之前被阻塞的信号会立即递达到进程。

信号被阻塞——>信号一定是未决状态

block表 ,pending表 ,handler表

在内核中,信号是一种异步事件,可能随时被发送给进程,并且进程需要及时响应。为了管理信号的处理过程,内核维护了三个重要的数据结构:block表、pending表和handler表。
在这里插入图片描述

  1. block表:用于记录被阻塞的信号集合。当一个进程调用sigprocmask函数时,它可以指定一组要阻塞的信号。这些信号会被放入该进程对应的block表中,使得它们在阻塞状态下不会递达到该进程。当进程需要解除对某个信号的阻塞时,可以再次调用sigprocmask函数来修改block表。

  2. pending表:用于记录未决的信号集合。当一个信号递达到目标进程时,如果目标进程正在处理另外一个相同的信号,那么这个信号就会被标记为未决状态,放入该进程对应的pending表中。当当前信号处理完毕后,内核会检查pending表中是否有未决的信号,如果有,则将它们取出并递达到进程。

  3. handler表:用于记录每种信号对应的信号处理函数。当一个信号递达到目标进程时,内核会根据该信号对应的handler表中的处理函数来执行相应的操作。如果进程没有安装该信号的处理函数,则会执行默认的信号处理行为。

这些表都是在进程控制块(PCB)中维护的,并且可以通过一些系统调用和库函数来修改和查询。例如,sigprocmask函数可以修改block表,sigpending函数可以查询pending表,signal和sigaction函数可以修改handler表。

sigset_t类型

sigset_t 是一个数据类型,用于表示一组信号的集合。在 POSIX 标准中,sigset_t 被定义为一个整数数组。

使用 sigset_t 可以方便地管理进程的信号屏蔽字和未决信号集合。进程的信号屏蔽字是一个 sigset_t 类型的变量,它用于标记哪些信号是被阻塞的。当一个信号被阻塞时,即使该信号有递达请求,也不会发送给进程。我们可以使用 sigprocmask 系统调用来修改进程的信号屏蔽字(信号屏蔽集合)。

另外,sigset_t 还可以用于查询进程的未决信号集合。未决信号集合记录了已经递达到进程,但尚未被处理的信号。我们可以使用 sigpending 系统调用来查询未决信号集合。该函数会将未决信号集合写入 sigset_t 类型的变量中返回。

在使用 sigset_t 时,我们可以使用一些辅助函数来对信号集合进行操作。例如:

  • sigemptyset:将一个信号集合清空,即将该集合中所有信号都设置为未包含状态。
  • sigfillset:将一个信号集合填充满,即将该集合中所有信号都设置为包含状态。
  • sigaddset:将一个信号添加到信号集合中。
  • sigdelset:将一个信号从信号集合中删除。

这些辅助函数可以方便我们对信号集合进行操作,从而更好地管理进程的信号处理。

👉🏻信号集操作函数

常见信号集操作函数

当使用 sigset_t 表示信号集合时,可以使用以下函数进行信号集合的操作:

  1. int sigemptyset(sigset_t *set)
    该函数用于清空信号集合,将所有信号都设置为未包含状态(比特位清0)。它会将 set 指向的信号集合清空,成功返回0,失败返回-1。

  2. int sigfillset(sigset_t *set)
    该函数用于填充信号集合,将所有信号都设置为包含状态(比特位置为1)。它会将 set 指向的信号集合填充满,成功返回0,失败返回-1。

  3. int sigaddset(sigset_t *set, int signum)
    该函数用于将指定的信号添加到信号集合中。set 是要操作的信号集合的指针,signum 是要添加的信号编号。成功返回0,失败返回-1。

  4. int sigdelset(sigset_t *set, int signum)
    该函数用于从信号集合中删除指定的信号。set 是要操作的信号集合的指针,signum 是要删除的信号编号。成功返回0,失败返回-1。

  5. int sigismember(const sigset_t *set, int signum)
    该函数用于检查指定的信号是否在信号集合中。set 是要检查的信号集合的指针,signum 是要检查的信号编号。如果信号在信号集合中,返回1;如果信号不在信号集合中,返回0;如果发生错误,返回-1。

这些函数可以帮助我们方便地对信号集合进行操作,例如创建空的信号集合将所有信号添加到信号集合中从信号集合中删除特定的信号检查信号是否在信号集合中等。


🌧 以下是每个函数的用法示例

  1. int sigemptyset(sigset_t *set)
    该函数用于清空信号集合,将所有信号都设置为未包含状态。
#include <signal.h>

int main() {
    sigset_t set;
    sigemptyset(&set);  // 清空信号集合
    return 0;
}
  1. int sigfillset(sigset_t *set)
    该函数用于填充信号集合,将所有信号都设置为包含状态。
#include <signal.h>

int main() {
    sigset_t set;
    sigfillset(&set);  // 填充信号集合
    return 0;
}
  1. int sigaddset(sigset_t *set, int signum)
    该函数用于将指定的信号添加到信号集合中。
#include <signal.h>

int main() {
    sigset_t set;
    sigemptyset(&set);  // 清空信号集合
    sigaddset(&set, SIGINT);  // 将 SIGINT 信号添加到信号集合中
    return 0;
}
  1. int sigdelset(sigset_t *set, int signum)
    该函数用于从信号集合中删除指定的信号。
#include <signal.h>

int main() {
    sigset_t set;
    sigfillset(&set);  // 填充信号集合
    sigdelset(&set, SIGINT);  // 从信号集合中删除 SIGINT 信号
    return 0;
}
  1. int sigismember(const sigset_t *set, int signum)
    该函数用于检查指定的信号是否在信号集合中。
#include <signal.h>
#include <stdio.h>

int main() {
    sigset_t set;
    sigemptyset(&set);  // 清空信号集合
    sigaddset(&set, SIGINT);  // 将 SIGINT 信号添加到信号集合中

    if (sigismember(&set, SIGINT)) {
        printf("SIGINT is a member of the signal set\n");
    } else {
        printf("SIGINT is not a member of the signal set\n");
    }

    return 0;
}

sigaction函数

sigaction函数是用于设置和修改信号处理函数的系统调用。通过调用该函数,可以为特定的信号注册一个信号处理函数,并指定信号处理的行为。

sigaction函数的原型如下:

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

参数说明:

  • signum:表示要注册的信号。
  • act:一个指向struct sigaction类型的指针,用于指定新的信号处理函数以及信号处理的行为。
  • oldact:一个指向struct sigaction类型的指针,用于保存之前的信号处理函数以及信号处理的行为。

函数返回值为0表示成功,返回-1表示出错。

下面是一个简单的示例程序,演示了如何使用sigaction函数:

#include <stdio.h>
#include <signal.h>

void handler(int sig)
{
    printf("Received signal %d\n", sig);
}

int main()
{
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    // 注册信号处理函数
    sigaction(SIGINT, &sa, NULL);

    while(1) {}

    return 0;
}

在这个示例程序中,首先定义了一个信号处理函数handler来处理 SIGINT 信号。然后创建了一个struct sigaction类型的结构体sa,并将其中的sa_handler成员设置为handler,其他成员设置为默认值。接着调用sigaction函数,为 SIGINT 信号注册了信号处理函数sa。

最后程序进入一个无限循环,等待 SIGINT 信号的到来。当进程收到 SIGINT 信号时,会调用事先注册的信号处理函数handler来处理该信号,并打印一些信息。

通过使用sigaction函数,可以为特定的信号注册一个信号处理函数,并指定信号处理的行为。与signal函数相比,sigaction函数提供了更多的灵活性和可靠性。

sigprocmask函数

sigprocmask函数是一个用于设置和修改进程信号屏蔽字的系统调用。通过调用该函数,可以控制进程对特定信号的处理方式。

sigprocmask函数的原型如下:

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

参数说明:

  • how:表示如何修改信号屏蔽字的方式,可以取以下值:

    • SIG_BLOCK:将set中的信号添加到当前进程的信号屏蔽字中,即阻塞这些信号。(oldset原有的基础上添加新的信号屏蔽字)
    • SIG_UNBLOCK:从当前进程的信号屏蔽字中移除set中的信号,即解除对这些信号的阻塞。
    • SIG_SETMASK:将当前进程的信号屏蔽字设置为set中的值,即使用set中的信号屏蔽字替换当前进程的信号屏蔽字。
      在这里插入图片描述
  • set:一个指向sigset_t类型的指针,用于指定要修改的信号集合。

  • oldset:一个指向sigset_t类型的指针,用于保存之前的信号屏蔽字。

函数返回值为0表示成功,返回-1表示出错。

下面是一个简单的示例程序,演示了如何使用sigprocmask函数:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int sig)
{
    printf("Received signal %d\n", sig);
}

int main()
{
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    // 注册信号处理函数
    sigaction(SIGINT, &sa, NULL);

    printf("Blocking SIGINT...\n");

    // 阻塞 SIGINT 信号
    sigset_t set, oldset;
    sigemptyset(&set);
     sigemptyset(&oldset);//先都清空
    sigaddset(&set, SIGINT);
    sigprocmask(SIG_BLOCK, &set, &oldset);

    printf("SIGINT is blocked. Sleeping for 10 seconds...\n");
    sleep(10);

    printf("Unblocking SIGINT...\n");

    // 解除对 SIGINT 信号的阻塞
    sigprocmask(SIG_SETMASK, &oldset, NULL);

    printf("SIGINT is unblocked. Sleeping for 10 seconds...\n");
    sleep(10);

    return 0;
}

在这个示例程序中,首先注册了一个信号处理函数handler来处理 SIGINT 信号。然后调用sigprocmask函数,将 SIGINT 信号添加到进程的信号屏蔽字中,即阻塞 SIGINT 信号。之后程序会打印一些信息,并休眠10秒钟。在这段时间内,如果进程收到 SIGINT 信号,则该信号会被暂时挂起,直到解除对该信号的阻塞。

接着,程序调用sigprocmask函数解除对 SIGINT 信号的阻塞,再次打印一些信息并休眠10秒钟。在这段时间内,如果进程收到 SIGINT 信号,则会调用事先注册的信号处理函数handler来处理该信号。

sigpending函数

sigpending函数用于获取当前进程未决的信号集,即已经发送但尚未被进程处理的信号集。

sigpending函数的原型如下:

int sigpending(sigset_t *set);

参数说明:

  • set:一个指向sigset_t类型的指针,用于保存未决信号集。

函数返回值为0表示成功,返回-1表示出错。

下面是一个简单的示例程序,演示了如何使用sigpending函数:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int sig)
{
    printf("Received signal %d\n", sig);
}

int main()
{
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    // 注册信号处理函数
    sigaction(SIGUSR1, &sa, NULL);

    // 发送 SIGUSR1 信号
    printf("Sending SIGUSR1...\n");
    kill(getpid(), SIGUSR1);

    // 检查未决信号集
    sigset_t set;
    sigpending(&set);

    if (sigismember(&set, SIGUSR1)) {
        printf("SIGUSR1 is pending\n");
    } else {
        printf("SIGUSR1 is not pending\n");
    }

    return 0;
}

在这个示例程序中,首先定义了一个信号处理函数handler来处理 SIGUSR1 信号。然后创建了一个struct sigaction类型的结构体sa,并将其中的sa_handler成员设置为handler,其他成员设置为默认值。接着调用sigaction函数,为 SIGUSR1 信号注册了信号处理函数sa。

然后程序通过kill函数向当前进程发送了 SIGUSR1 信号。接着调用sigpending函数,获取当前进程的未决信号集,并将结果保存在set中。然后使用sigismember函数判断 SIGUSR1 是否在未决信号集中,如果是,则打印相应的信息。

通过使用sigpending函数,可以获取当前进程未决的信号集,即已经发送但尚未被进程处理的信号集。这对于需要了解当前进程是否收到某个信号以及是否处理了该信号非常有用。

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

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

相关文章

软考20-上午题-串及其模式匹配

串&#xff08;字符串&#xff09;是一种特殊的线性表&#xff0c;其数据元素为字符。如&#xff1a;"abc"。 一、串的定义 由字符构成的有限序列&#xff0c;是一种线性表。 串的比较&#xff1a;以字符的ASCII值作为依据。比较操作从两个字符串的第一个字符开始&a…

Openresty+Lua+Redis实现高性能缓存

一、背景 当我们的程序需要提供较高的并发访问时&#xff0c;往往需要在程序中引入缓存技术&#xff0c;通常都是使用Redis作为缓存&#xff0c;但是要再更进一步提升性能的话&#xff0c;就需要尽可能的减少请求的链路长度&#xff0c;比如可以将访问Redis缓存从Tomcat服务器…

4. 树(二叉树、二叉查找树/二叉排序树/二叉搜索树、平衡二叉树、平衡二叉B树/红黑树)

树 1. 二叉树1.1 概述1.2 特点1.3 二叉树遍历方式1.3.1 前序遍历(先序遍历)1.3.2 中序遍历1.3.3 后序遍历1.3.4 层序遍历 2. 二叉查找树&#xff08;二叉排序树、二叉搜索树&#xff09;2.1 概述2.2 特点 3. 平衡二叉树3.1 概述3.2 特点3.3 旋转3.3.1 左旋3.3.2 右旋 3.4 平衡二…

Quartus IP 之mif与hex文件创建与使用

一、mif与hex概述 ROM IP的数据需要满足断电不丢失的要求&#xff0c;ROM IP数据的文件格式一般有三种文件格式&#xff1a;.mif、.hex、.coe&#xff0c;Xilinx与Intel Altera支持的ROM IP数据文件格式如下&#xff1a; Xilinx与Altera支持的ROM文件格式 Alterahex、mifAM&am…

JS第二天、原型、原型链、正则

☆☆☆☆ 什么是原型&#xff1f; 构造函数的prototype 就是原型 专门保存所有子对象共有属性和方法的对象一个对象的原型就是它的构造函数的prototype属性的值。prototype是哪来的&#xff1f;所有的函数都有一个prototype属性当函数被创建的时候&#xff0c;prototype属性…

项目02《游戏-08-开发》Unity3D

基于 项目02《游戏-07-开发》Unity3D &#xff0c; 本次任务做物品相互与详情的功能&#xff0c; 首先要做 点击相应&#xff0c; 接下来用接口实现点击相应事件&#xff0c;具体到代码中&#xff0c;我们找到需要响应鼠标事件的对象&#xff0c; 双击PackageCell…

食堂预约系统

文章目录 前言​部分沟通内容技术点小程序功能部分代码段功能图 商家管理系统功能说明功能图登录页面商家管理页面 食品管理订单管理其他功能 结束语 前言​ 最近&#xff0c;接了个小项目——学校食堂预约取餐系统。 具体需求如下图&#xff1a; 部分沟通内容 技术点 系统…

C++:模板初阶

泛型编程 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;是代码复用的一种手段。模板是泛型编程的基础。 函数模板 函数模板代表了一个函数家族&#xff0c;该函数模板与类型无关&#xff0c;在使用时被参数化&#xff0c;根据实参类型产生函数的特定类型版本。…

百面嵌入式专栏(面试题)网络编程面试题

沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们将介绍网络编程面试题 。 1、什么是IO多路复用 I/O多路复用的本质是使用select,poll或者epoll函数,挂起进程,当一个或者多个I/O事件发生之后,将控制返回给用户进程。以服务器编程为例,传统的多进程(多线程…

antv/x6 边添加鼠标悬浮高亮和删除功能

antv/x6 边添加鼠标悬浮高亮和删除功能 效果添加悬浮效果和删除工具取消悬浮效果边删除后的回调函数 效果 添加悬浮效果和删除工具 this.graph.on(edge:mouseenter, ({ cell }) > {let cellId cell.store.data.source.celllet sourceCell _this.graph.getCellById(cellId…

绝地求生:盘点游戏内七款真人脸模,你最喜欢哪款?

从27.1版本更新后&#xff0c;游戏内上线了荣都地图代言人吴彦祖和李政宰的真人脸模&#xff0c;从此闲游盒的各位盒友灵魂搭配的资源库里又多了两位英俊脸庞&#xff0c;那么今天闲游盒来盘点一下游戏内上线的七款真人脸模&#xff0c;看看大家更喜欢哪款呢? 吴彦祖和李政宰 …

CSS-IN-JS

CSS-IN-JS 为什么会有CSS-IN-JS CSS-IN-JS是web项目中将CSS代码捆绑在JavaScript代码中的解决方案。 这种方案旨在解决CSS的局限性&#xff0c;例如缺乏动态功能&#xff0c;作用域和可移植性。 CSS-IN-JS介绍 1&#xff1a;CSS-IN-JS方案的优点&#xff1a; 让css代码拥…

【MySQL】DQL的总结和案例学习

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-VWRkWqFrRMi4uLRa {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

bert分类模型使用

使用 bert-bert-chinese 预训练模型去做分类任务&#xff0c;这里找了新闻分类数据&#xff0c;数据有 20w&#xff0c;来自https://github.com/649453932/Bert-Chinese-Text-Classification-Pytorch/tree/master/THUCNews 数据 20w &#xff0c;18w 训练数据&#xff0c;1w 验…

挑战!贪吃蛇小游戏的实现(1)

引言 相信大家都玩过贪吃蛇这个游戏&#xff01; 玩家控制一个不断移动的蛇形角色&#xff0c;在一个封闭空间内移动。随着时间推进&#xff0c;这个蛇形角色会逐渐增长&#xff0c;通常是通过吞食屏幕上出现的物品&#xff08;如点或者其他标志&#xff09;来实现。每当贪吃…

JQuery动态插入Bootstrap模态框(Modal)

这里所说的动态插入&#xff0c;是指用JS的append()方式追加元素内容&#xff0c;而不是静态写在HTML里面。 为什么会用到这种方式呢&#xff1f;比如登录框。有些网站在大部分页面都有登录按钮&#xff0c;如果是用Bootstrap的模态框调用的话&#xff0c;常规方式都是写在HTM…

目标检测及相关算法介绍

文章目录 目标检测介绍目标检测算法分类目标检测算法模型组成经典目标检测论文 目标检测介绍 目标检测是计算机视觉领域中的一项重要任务&#xff0c;旨在识别图像或视频中的特定对象的位置并将其与不同类别中的对象进行分类。与图像分类任务不同&#xff0c;目标检测不仅需要…

vue全家桶之状态管理Pinia

一、Pinia和Vuex的对比 1.什么是Pinia呢&#xff1f; Pinia&#xff08;发音为/piːnjʌ/&#xff0c;如英语中的“peenya”&#xff09;是最接近pia&#xff08;西班牙语中的菠萝&#xff09;的词&#xff1b; Pinia开始于大概2019年&#xff0c;最初是作为一个实验为Vue重新…

详解C++类和对象(上)

文章目录 写在前面1. 类的定义2. 类的访问限定符及封装2.1 类的访问限定符2.2 封装 3. 类的作用域4. 类的实例化5 类的对象大小的计算6. 类成员函数的this指针 写在前面 类和对象这一章节&#xff0c;分为上、中、下三篇文章进行拆分介绍的&#xff0c;本篇文章介绍了类和对象…

LabVIEW与EtherCAT实现风洞安全联锁及状态监测

LabVIEW与EtherCAT实现风洞安全联锁及状态监测 在现代风洞试验中&#xff0c;安全联锁与状态监测系统发挥着至关重要的作用&#xff0c;确保了试验过程的安全性与高效性。介绍了一套基于EtherCAT总线技术和LabVIEW软件开发的风洞安全联锁及状态监测系统。该系统通过实时、可靠…
最新文章