【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.hqwc.cn/news/452404.html

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

相关文章

字符串左旋

题目&#xff1a;字符串左旋 内容&#xff1a;实现一个函数&#xff0c;可以左旋字符串中的K个字符。 例如&#xff1a; ABCDEF左旋一个字符可以得到BCDEFA ABCDEF左旋两个字符可以得到CDEFAB 方法一&#xff1a;移动字符 #include <stdio.h> #include <string.h>c…

Faster-RCNN 和 Mask-RCNN详解

Faster-RCNN &#xff0c;Mask-RCNN原理 一、摘要1.1 图像分割1.2 语义分割与实例分割 二、Faster-RCNN2.1 Faster-RCNN模型架构2.2 &#x1f34a;深度卷积网络&#xff08;backbone&#xff09;2.3 &#x1f34e;RPN&#xff08;Region Proposal Network&#xff09;2.4 &…

VS2019 添加程序包

dotnet add package AlibabaCloud.SDK.Bailian20230601 来提示添加程序包 选择菜单栏 项目----管理NuGet程序包 输入程序包的名称&#xff0c;然后添加即可&#xff0c; 这只是给当前工程添加&#xff0c;并不是给VS添加&#xff0c;所以你打开新工程&#xff0c;需要使用的话…

Android BitmapShader setLocalMatrix缩放Bitmap高度重新onMeasure,Kotlin

Android BitmapShader setLocalMatrix缩放Bitmap高度重新onMeasure&#xff0c;Kotlin <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://sc…

ps基本操作

目录 ps基本操作 ps基本操作

【C++入门学习指南】:函数重载提升代码清晰度与灵活性

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; C入门到进阶 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、函数重载1.1 函数重载的概念1.2 函数重载的作用1.3 C支持函数重载的原理1.4 扩展 &…

Kubernetes基础(十一)-CNI网络插件用法和对比

1 CNI概述 1.1 什么是CNI&#xff1f; Kubernetes 本身并没有实现自己的容器网络&#xff0c;而是借助 CNI 标准&#xff0c;通过插件化的方式来集成各种网络插件&#xff0c;实现集群内部网络相互通信。 CNI&#xff08;Container Network Interface&#xff0c;容器网络的…

Leetcode—535. TinyURL 的加密与解密【中等】

2024每日刷题&#xff08;110&#xff09; Leetcode—535. TinyURL 的加密与解密 实现代码 class Solution { public:// Encodes a URL to a shortened URL.string encode(string longUrl) {while(!urlToCode.count(longUrl)) {string code;for(int i 0; i < 6; i) {code…

【01】C++入门

文章目录 Ⅰ 命名空间1. 命名空间域的产生2. 命名空间域的定义3. 命名空间域的使用 Ⅱ 缺省参数1. 缺省的概念2. 缺省的分类3. 声明和定义不能同时存在缺省参数 Ⅲ 函数重载1. 函数重载概念2. 编译器如何实现函数重载 Ⅳ 引用1. 引用的概念2. 引用的特性3. 引用的使用场景4. 引…

云服务器也能挂游戏 安卓模拟器

安卓模拟器云服务器 什么是BlueStacks模拟器主机&#xff1f; 特网科技基于Windows操作系统预装了BlueStacks Android模拟器您能够通过Android模拟器安装Android应用程序、如APP游戏、安卓APP、APP游戏等。 我可以在主机上安装应用程序吗&#xff1f; 你可以在BlueStacks模…

css1基础选择器

大纲 一.标签选择器 比较简单&#xff0c;前面直接写目标标签 二.类选择器 应用 例子 三.多类名选择器&#xff08;调用时中间用空格隔开&#xff09; 四.id选择器 应用 五.通配符选择器 应用 六.总结

汽车租赁系统

目录 一.研究背景 二.系统架构 1、SSM 2、JAVA 3、MySQL 4、系统架构 三.系统功能 1、车辆管理 2、客户管理 3、销售管理 4、统计分析 四.系统实现 五.结论总结 一.研究背景 传统的销售与信息统计管理都主要依靠人工&#xff0c;处理出的销售数据量与使用管理系统…