信号-进程间通信

信号

1. 信号概述

在 Linux 操作系统中,信号是一种进程间通信的机制,用于通知进程发生了某个事件。信号可以由内核、其他进程,或者进程自身发送。每个信号都对应一个特定的事件或异常,例如进程终止、Ctrl+C 中断等。

本质上是一个整数,不同的信号对应不同的值,由于信号的结构简单所以天生不能携带很大的信息量,但是信号在系统中的优先级是非常高的。非常不建议使用信号进行进程间通信。

1.1 信号编号

通过 kill -l 命令可以察看系统定义的信号列表:

# 执行shell命令查看信号
$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

常见的 Linux 信号:

  1. SIGHUP (1): 终端挂起或控制进程终止。
  2. SIGINT (2): 用户发送中断信号(Ctrl+C)。
  3. SIGQUIT (3): 用户发送退出信号(Ctrl+\)。
  4. SIGILL (4): 检测到非法指令。
  5. SIGABRT (6): 调用 abort 函数,用于异常终止进程。
  6. SIGFPE (8): 浮点异常,如除以零。
  7. SIGKILL (9): 强制终止进程,无法被捕获或忽略。
  8. SIGSEGV (11): 段错误,试图访问未分配的内存。
  9. SIGPIPE (13): 向没有读取端口的管道写入数据。
  10. SIGALRM (14): 定时器超时。
  11. SIGTERM (15): 终止信号,用于请求进程正常终止。
  12. SIGUSR1 (10): 用户定义信号1。
  13. SIGUSR2 (12): 用户定义信号2。
1.2 查看信号信息

通过Linux提供的 man 文档可以查询所有信号的详细信息:

# 查看man文档的信号描述
$ man 7 signal

在信号描述中介绍了对产生的信号的五种默认处理动作,分别是:

  • Term:信号将进程终止

  • Ign:信号产生之后默认被忽略了

  • Core:信号将进程终止, 并且生成一个core文件(一般用于gdb调试)

  • Stop:信号会暂停进程的运行

  • Cont:信号会让暂停的进程继续运行

关于对信号的介绍有一句非常重要的描述:

The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.

9号信号和19号信号不能被 捕捉, 阻塞, 和 忽略

  • 9号信号: 无条件杀死进程
  • 19号信号: 无条件暂停进程
1.3 信号的状态

在 Linux 中,信号可以有三种基本状态:未决(Pending)、阻塞(Blocked)、以及默认状态。这些状态描述了信号的当前处理情况。

  1. 未决状态(Pending):
    • 当一个信号产生时,它首先进入未决状态,表示该信号已经发生但尚未被处理
    • 如果多次产生相同的信号,未决状态只记录一次,不会累积。
  2. 阻塞状态(Blocked):
    • 进程可以选择阻塞(屏蔽)某些信号,使得这些信号在阻塞状态时不会被处理,而是保持在未决状态。
    • 阻塞状态是一种对信号的暂时性忽略,当信号被解除阻塞后,它会根据相应的处理方式处理。
  3. 默认状态:
    • 对于每种信号,都可以设置默认的处理方式,包括终止进程(Terminate)、忽略信号(Ignore)或执行用户自定义的处理函数(Handler)。
    • 默认状态是在信号产生时,如果未设置其他处理方式,则采用的方式。

2.信号相关函数

2.1 kill/raise/abort

kill 函数:

  • 用于向指定进程或进程组发送信号。

  • #include <signal.h>
    int kill(pid_t pid, int sig);
    
  • 参数 pid 表示进程或进程组的 ID,sig 表示要发送的信号编号。

raise 函数:

  • 用于向当前进程自身发送信号。

  • #include <signal.h>
    int raise(int sig);
    
  • 参数 sig 表示要发送的信号编号。

abort函数:

  • 给当前进程发送一个固定信号 (SIGABRT)
// 这是一个中断函数, 调用这个函数, 发送一个固定信号 (SIGABRT), 杀死当前进程
#include <stdlib.h>
void abort(void);
2.2 定时器(信号捕捉)
alarm函数

alarm 函数是一个定时器函数,用于在指定时间后产生 SIGALRM 信号。它允许程序员设置一个定时器,当定时器超时时,内核将向进程发送 SIGALRM 信号。通常,SIGALRM 的默认操作是终止进程。

以下是 alarm 函数的基本形式:

#include <unistd.h>

unsigned int alarm(unsigned int seconds);
  • seconds 参数表示设置的定时器时间,以秒为单位。
  • 函数返回上一次设置的剩余时间(如果有),或者0(如果没有之前的定时器)。

使用 alarm 函数的一个常见用途是在程序中设置一个超时时间,以便在等待某个事件发生时避免无限期地阻塞。

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

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

// SIGALRM 信号处理函数
void alarm_handler(int signum) {
    printf("Received SIGALRM\n");
}

int main() {
    // 设置 SIGALRM 的处理函数
    // 当程序接收到 SIGALRM 信号时,将调用 alarm_handler 函数来处理这个信号。
    signal(SIGALRM, alarm_handler);

    // 设置定时器,5 秒后发送 SIGALRM 信号
    unsigned int remaining_time = alarm(5);
    printf("Alarm set. Remaining time: %u seconds\n", remaining_time);

    // 模拟一些工作,等待超时
    sleep(7);

    // 如果在超时前收到了 SIGALRM,处理函数将被调用
    printf("Work done\n");

    return 0;
}
setitimer函数

setitimer () 函数可以进行周期性定时,每触发一次定时器就会发射出一个信号

// 这个函数可以实现周期性定时, 每个一段固定的时间, 发出一个特定的定时器信号
#include <sys/time.h>

struct itimerval {
	struct timeval it_interval; /* 时间间隔 */
	struct timeval it_value;    /* 第一次触发定时器的时长 */
};
// 举例: luffy有一个闹钟, 并且使用这个闹钟定时:
// 早晨7点中起床, 第一次闹钟响起时可能起不来, 之后每隔5分钟再响一次
//  - it_value: 当前设置闹钟的时间点 到 明天早晨7点 对应的总秒数
//  - it_interval: 闹钟第一次响过之后, 每隔5分钟响一次

// 这个结构体表示的是一个时间段: tv_sec + tv_usec
struct timeval {
	time_t      tv_sec;         /* 秒 */
	suseconds_t tv_usec;        /* 微妙 */
};

int setitimer(int which, const struct itimerval *new_value, 
              struct itimerval *old_value);

参数:

  • which: 定时器使用什么样的计时法则, 不同的计时法则发出的信号不同
    • ITIMER_REAL: 自然计时法, 最常用, 发出的信号为SIGALRM, 一般使用这个宏值,自然计时法时间 = 用户区 + 内核 + 消耗的时间(从进程的用户区到内核区切换使用的总时间)
    • ITIMER_VIRTUAL: 只计算程序在用户区运行使用的时间,发射的信号为 SIGVTALRM
    • ITIMER_PROF: 只计算内核运行使用的时间, 发出的信号为SIGPROF
  • new_value: 给定时器设置的定时信息, 传入参数
  • old_value: 上一次给定时器设置的定时信息, 传出参数,如果不需要这个信息, 指定为NULL

例子:

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>

void timer_handler(int signum) {
    printf("Timer expired!\n");
}

int main() {
    // 设置 SIGALRM 信号处理函数
    signal(SIGALRM, timer_handler);

    // 设置定时器初始值和溢出后的处理方式
    struct itimerval timer;
    timer.it_value.tv_sec = 2;      // 初始值为2秒, 2s后第一次触发
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 1;   // 间隔为1秒,即每秒触发一次
    timer.it_interval.tv_usec = 0;

    // 设置定时器
    if (setitimer(ITIMER_REAL, &timer, NULL) == -1) {
        perror("setitimer");
        exit(EXIT_FAILURE);
    }

    // 让程序持续运行,观察定时器的触发
    while (1) {
        sleep(5);
    }

    return 0;
}

在这里插入图片描述

3. 信号集

3.1 信号集概述

信号集(Signal Set)是用于表示一组信号的数据结构。在 Unix/Linux 操作系统中,信号集被广泛用于进程管理中,主要用于设置、查询和修改进程的信号状态。信号集通常是一个二进制位图,每个位表示一个信号,位的状态表示信号的状态(屏蔽或未屏蔽)。

信号集的主要目的是允许进程选择性地阻塞或解除阻塞一组特定的信号,以实现对信号的灵活控制。以下是在 C 语言中使用信号集的相关函数和数据结构:

sigset_t 数据类型:

  • sigset_t 是用于存储信号集的数据类型,通常是一个整数或类似的位图结构。
  • 在头文件 <signal.h> 中定义,具体实现可能因系统而异。

在PCB中有两个非常重要的信号集。一个称之为“阻塞信号集”,另一个称之为“未决信号集”。这两个信号集体现在内核中就是两张表。

在阻塞信号集中,描述这个信号有没有被阻塞

  • 默认情况下没有信号是被阻塞的, 因此信号对应的标志位的值为 0
  • 如果某个信号被设置为了阻塞状态, 这个信号对应的标志位 被设置为 1

在未决信号集中, 描述信号是否处于未决状态

  • 如果这个信号被阻塞了, 不能处理, 这个信号对应的标志位被设置为1
  • 如果这个信号的阻塞被解除了, 未决信号集中的这个信号马上就被处理了, 这个信号对应的标志位值变为0
  • 如果这个信号没有阻塞, 信号产生之后直接被处理, 因此不会在未决信号集中做任何记录
3.2 信号集函数

阻塞信号集可以通过系统函数进行读写操作,未决信号集只能对其进行读操作。

读/写阻塞信号集的函数:

#include <signal.h>
// 使用这个函数修改内核中的阻塞信号集
// sigset_t 被封装之后得到的数据类型, 原型:int[32], 里边一共有1024给标志位, 每一个信号对应一个标志位
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

参数:

how:

  • SIG_BLOCK: 将参数 set 集合中的数据追加到阻塞信号集中
  • SIG_UNBLOCK: 将参数 set 集合中的信号在阻塞信号集中解除阻塞
  • SIG_SETMASK: 使用参 set 结合中的数据覆盖内核的阻塞信号集数据

oldset: 通过这个参数将设置之前的阻塞信号集数据传出,如果不需要可以指定为NULL

返回值:函数调用成功返回0,调用失败返回-1

sigprocmask() 函数有一个 sigset_t 类型的参数,对这种类型的数据进行初始化需要调用一些相关的操作函数:

#include <signal.h>
// 如果在程序中读写 sigset_t 类型的变量
// 阻塞信号集和未决信号集都存储在 sigset_t 类型的变量中, 这个变量对应一块内存
// 阻塞信号集和未决信号集, 对应的内存中有1024bit = 128字节

// 将set集合中所有的标志位设置为0
int sigemptyset(sigset_t *set);
// 将set集合中所有的标志位设置为1
int sigfillset(sigset_t *set);
// 将set集合中某一个信号(signum)对应的标志位设置为1
int sigaddset(sigset_t *set, int signum);
// 将set集合中某一个信号(signum)对应的标志位设置为0
int sigdelset(sigset_t *set, int signum);
// 判断某个信号在集合中对应的标志位到底是0还是1, 如果是0返回0, 如果是1返回1
int sigismember(const sigset_t *set, int signum);

读未决信号集的操作函数:

#include <signal.h>
// 这个函数的参数是传出参数, 传出的内核未决信号集的拷贝
// 读一下这个集合就指定哪个信号是未决状态
int sigpending(sigset_t *set);

下面举一个简单的例子,演示一下信号集操作函数的使用:

需求: 
在阻塞信号集中设置某些信号阻塞, 通过一些操作产生这些信号, 然后读未决信号集, 最后再解除这些信号的阻塞
假设阻塞这些信号: 
  - 2号信号: SIGINT: ctrl+c
  - 3号信号: SIGQUIT: ctrl+\
  - 9号信号: SIGKILL: 通过shell命令给进程发送这个信号 kill -9 PID
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

int main()
{
    // 1. 初始化信号集
    sigset_t myset;
    sigemptyset(&myset);
    // 设置阻塞的信号
    sigaddset(&myset, SIGINT);  // 2
    sigaddset(&myset, SIGQUIT); // 3
    sigaddset(&myset, SIGKILL); // 9 测试不能被阻塞

    // 2. 将初始化的信号集中的数据设置给内核
    sigset_t old;
    sigprocmask(SIG_BLOCK, &myset, &old);

    // 3. 让进程一直运行, 在当前进程中产生对应的信号
    int i = 0;
    while(1)
    {
        // 4. 读内核的未决信号集
        sigset_t curset;
        sigpending(&curset);
        // 遍历这个信号集
        for(int i=1; i<32; ++i)
        {
            int ret = sigismember(&curset, i);
            printf("%d", ret);
        }
        printf("\n");
        sleep(1);
        i++;
        if(i==10)
        {
            // 解除阻塞, 重新设置阻塞信号集
            //sigprocmask(SIG_UNBLOCK, &myset, NULL);
            sigprocmask(SIG_SETMASK, &old, NULL);
        }
    }
    return 0;
}

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

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

相关文章

使用AUTOSAR来开发汽车基础软件的优点

1、高质量。以前我们采用手写代码的方式&#xff0c;是几个工程师在战斗。现在我们采用平台&#xff0c;BSW代码都是供应商提供的&#xff0c;我们相当于后面还有一个团队陪着我们在战斗。 2、低成本。大家都说采用AUTOSAR平台好贵&#xff0c;但是从长远来看是值得的&#xff…

利用虾皮Shopee API (shopee.item_get)提升电商平台用户转化率与客单价

在当今的电商环境中&#xff0c;用户转化率和客单价是衡量电商平台成功与否的关键指标。虾皮Shopee作为一个领先的电商平台&#xff0c;提供了丰富的API服务&#xff0c;其中shopee.item_get接口允许商家根据商品ID获取详细的商品信息。通过合理利用这一API&#xff0c;商家可以…

glusterFS

一. 概念 1. 介绍 gluster是一个横向扩展的分布式文件系统&#xff0c;可将来自多个服务器的磁盘存储资源整合到一个全局名称空间中&#xff0c;可以根据存储消耗需求快速调配额外的存储。它将自动故障转移作为主要功能. 分布式存储系统.集群式NAS存储.无集中式元数据服务,采…

笔记本摄像头模拟监控推送RTSP流

使用笔记本摄像头模拟监控推送RTSP流 一、基础安装软件准备 本文使用软件下载链接:下载地址 FFmpeg软件: Download ffmpeg 选择Windows builds by BtbN 一个完整的跨平台解决方案&#xff0c;用于录制、转换和流式传输音频和视频。 EasyDarwin软件&#xff1a;Download Easy…

激活函数整理

sigmoid函数 import torch from d2l import torch as d2l %matplotlib inline ​ xtorch.arange(-10,10,0.1,requires_gradTrue) sigmoidtorch.nn.Sigmoid() ysigmoid(x) ​ d2l.plot(x.detach(),y.detach(),x,sigmoid(x),figsize(5,2.5)) sigmoid函数连续、光滑、单调递增&am…

java数据结构与算法刷题-----LeetCode343. 整数拆分(TODO)

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难&#xff0c;但它就是固定套路而已。其实动态规划只…

C++力扣题目226--翻转二叉树

给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&#xff1a;[2,3,1]示例 3&#x…

【算法与数据结构】746、LeetCode使用最小花费爬楼梯

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题可以从0阶或者1阶台阶开始&#xff0c;每次爬楼梯所需的花费是之前的花费dp[i]从本层向上爬所需的…

入门实战丨Python小游戏经典案例

文章目录 写在前面判断与循环小游戏猜数游戏龙的世界 写在后面 写在前面 本期内容&#xff1a;两个个简单的Python小游戏入门案例。 实验需求&#xff1a;python 实验目标&#xff1a;掌握基本的判断与循环语句。 判断与循环 判断与循环是编程中非常重要的两个概念&#x…

机器学习顶会ICML 2024今日开放投稿,CCF A类,中稿率27.94%(附ICML23杰出论文+18篇高分论文)

ICML 2024今天开放投稿了&#xff01;距离截稿还有24天&#xff0c;想冲ICML的同学速度&#xff01; ICML 全称 International Conference on Machine Learning&#xff0c;由国际机器学习学会&#xff08;IMLS&#xff09;举办&#xff0c;与NIPS一同被认为是人工智能、机器学…

面试宝典进阶之redis缓存面试题

R1、【初级】Redis常用的数据类型有哪些&#xff1f; &#xff08;1&#xff09;String&#xff08;字符串&#xff09; &#xff08;2&#xff09;Hash&#xff08;哈希&#xff09; &#xff08;3&#xff09;List&#xff08;列表&#xff09; &#xff08;4&#xff09;Se…

程序员面试技巧:成为HR心动的程序猿

文章目录 程序员必备的面试技巧导语一、准备充分二、突出亮点三、展示解决问题的能力四、良好的沟通能力五、积极展示学习态度示例结语&#x1f636; 写在结尾 程序员必备的面试技巧 “程序员必备的面试技巧&#xff0c;就像是编写一段完美的代码一样重要。在面试战场上&#…

vue3 +TS 安装使用pinia状态管理

目录 一.安装 1.下载安装依赖 2.创建src/stores/index.ts文件 3.创建src/stores/states.ts文件 4.创建src/stores/interface/index.ts文件 5.修改main.ts 6.目录结构如下 7.测试使用 8.去到首页点击按钮&#xff0c;打开控制台查看 一.安装 1.下载安装依赖 npm insta…

人类认知中的等价机理与机器智能中等价机理

人类认知中的等价机理是指人们在认知过程中&#xff0c;通过将不同的概念、事物或情境进行等价替代&#xff0c;从而实现思维的连贯和理解的补充。例如&#xff0c;当人们看到一个陌生的动物时&#xff0c;可以将它与已知的动物进行等价对应&#xff0c;从而理解其特征和行为。…

基于SpringBoot的毕业生实习与就业管理系统(系统+数据库+文档)

&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目 希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;一、绪论 1. 研究背景 现在大家…

私域流量转化差,这些问题你都解决了吗?

一、流量不精准 这是一个常见而又经常被忽视的问题。许多企业在私域运营中面临转化率低下的问题&#xff0c;但有没有想过&#xff0c;这可能只是因为你吸引的流量与你的产品不匹配&#xff1f; 从公域引流到私域&#xff0c;数量并非唯一关键&#xff0c;精准度更是重中之重…

如何在移动应用程序的 POC、原型和 MVP 之间做出选择?

许多企业家、企业和行业在决定是否将移动应用程序开发理念作为概念验证 (POC)、最小可行产品 (MVP)、原型或组合来推进时面临着挑战。 由于这三种方法对其利用都有各自的影响&#xff0c;因此正确理解每个方面并选择合适的方法将有助于利益相关者最大限度地提高其想法在用户和所…

送货单打印要用什么打印机和软件

在打印送货单时&#xff0c;打印机和软件的选择都是非常重要的。根据需求&#xff0c;可以选择喷墨打印机、激光打印机或针式打印机等类型&#xff0c;而软件我们可以选择专业的送货单打印软件&#xff0c;例如&#xff1a;方可销售送货单软件&#xff08;推荐&#xff09;就是…

Banner设计专家详细解释和使用技巧!

一、banner的作用 宝安在运营工作中具有吸引注意力、提高转化率、传达信息、提升品牌形象、引导用户行为、营造活动氛围等多种功能。因此&#xff0c;在运营工作中&#xff0c;需要根据具体需要和目标精心设计和合理使用宝安&#xff0c;才能达到更好的运营效果。 二、banner…

生信 R语言

11.芯片表达矩阵下游分析 ​rm(list ls())#清除所有变量 options(stringsAsFactors F) #BiocManager::install("CLL") suppressPackageStartupMessages(library(CLL)) data("sCLLex") sCLLex ## ExpressionSet (storageMode: lockedEnvironment) ## as…