Linux信号的保存

目录

一、信号的基本概念

二、信号在内核中的表示

三、信号集(sigset_t)与操作函数

1. 信号集操作函数

2. 示例代码

四、信号屏蔽与未决信号集操作

1. sigprocmask 函数

2. sigpending 函数

3. 示例代码


一、信号的基本概念

        信号是软件中断的一种形式,它允许程序异步地处理事件。当一个信号被发送到进程时,操作系统会中断该进程的正常执行流程,并转而去执行与该信号相关的处理程序。

在信号处理中,有几个关键概念需要明确:

  • 信号递达(Delivery) :实际执行信号处理动作的时刻,就像信件最终被收件人签收。

  • 信号未决(Pending) :信号从产生到递达之间的状态,此时信号就像已发出但还未被接收的信件,处于等待处理的状态。

  • 信号阻塞(Block) :进程可以选择阻塞某个信号,被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。阻塞和忽略是不同的概念,阻塞是让信号暂时无法递达,而忽略是在信号递达后选择不进行处理

二、信号在内核中的表示

在内核中,每个信号都有三个关键元素来描述其状态和处理方式:

  • 阻塞标志位(Block) :表示该信号是否被阻塞。

  • 未决标志位(Pending) :表示该信号是否处于未决状态。

  • 处理动作(Handler) :一个函数指针,指向该信号递达时的处理动作,可以是默认动作、忽略或者用户自定义的处理函数。

信号在内核中的表示示意图:

🍇举个栗子:

        假设我们有三个信号:SIGHUP、SIGINT 和 SIGQUIT。SIGHUP 信号未阻塞也未产生过,当它递达时执行默认处理动作;SIGINT 信号产生过但正在被阻塞,所以暂时不能递达,虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号;SIGQUIT 信号未产生过,一旦产生将被阻塞,它的处理动作是用户自定义函数 sighandler。

三、信号集(sigset_t)与操作函数

        为了方便对信号进行批量操作,Linux 提供了信号集(sigset_t)的概念。信号集是一种数据结构,用于表示一组信号的状态,每个信号在信号集中用一个比特位来表示其 “有效” 或 “无效” 状态。

1. 信号集操作函数

  • sigemptyset :初始化信号集,将所有信号的对应比特位清零,表示该信号集不包含任何有效信号。

  • sigfillset :初始化信号集,将所有信号的对应比特位置位,表示该信号集的有效信号包括系统支持的所有信号。

  • sigaddset :在已初始化的信号集中添加指定信号,将其对应比特位置位。

  • sigdelset :在已初始化的信号集中删除指定信号,将其对应比特位清零。

  • sigismember :判断一个信号是否在指定信号集中,返回值为 1 表示包含,0 表示不包含,-1 表示出错。

2. 示例代码

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

int main()
{
    sigset_t s; // 定义一个信号集变量

    sigemptyset(&s); // 初始化信号集,清空所有信号

    sigfillset(&s); // 填充信号集,包含所有信号

    sigaddset(&s, SIGINT); // 添加 SIGINT 信号到信号集

    sigdelset(&s, SIGINT); // 从信号集删除 SIGINT 信号

    int result = sigismember(&s, SIGINT); // 判断 SIGINT 是否在信号集中
    if (result == 1)
        printf("SIGINT is in the set\n");
    else if (result == 0)
        printf("SIGINT is not in the set\n");
    else
        printf("Error occurred\n");

    return 0;
}

四、信号屏蔽与未决信号集操作

1. sigprocmask 函数

sigprocmask 函数用于读取或更改进程的信号屏蔽字(阻塞信号集)。通过该函数,我们可以控制哪些信号被阻塞,从而影响信号的递达行为。

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
  • how 参数 :指定如何更改信号屏蔽字,可选值为 SIG_BLOCK(将 set 中的信号添加到当前屏蔽字)、SIG_UNBLOCK(将 set 中的信号从当前屏蔽字解除)和 SIG_SETMASK(将当前屏蔽字设置为 set 所指向的值)。

  • set 参数 :指向要设置的新信号集。

  • oset 参数 :用于保存原来的信号屏蔽字。

2. sigpending 函数

sigpending 函数用于读取进程的未决信号集,帮助我们了解哪些信号已经产生但还未被递达。

#include <signal.h>
int sigpending(sigset_t *set);

3. 示例代码

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

// 打印未决信号集
void printPending(sigset_t *pending)
{
    int i = 1;
    for (i = 1; i <= 31; i++)
    {
        if (sigismember(pending, i))
        {
            printf("1 ");
        }
        else
        {
            printf("0 ");
        }
    }
    printf("\n");
}

// 信号处理函数
void handler(int signo)
{
    printf("handler signo:%d\n", signo);
}

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

    sigset_t set, oset;
    sigemptyset(&set);
    sigemptyset(&oset);

    // 添加 SIGINT 信号到信号集
    sigaddset(&set, SIGINT);

    // 设置信号屏蔽字,阻塞 SIGINT 信号
    sigprocmask(SIG_SETMASK, &set, &oset);

    sigset_t pending;
    sigemptyset(&pending);

    int count = 0;
    while (1)
    {
        // 获取未决信号集
        sigpending(&pending);

        // 打印未决信号集
        printPending(&pending);

        sleep(1);

        count++;
        if (count == 7)
        {
            // 恢复原来的信号屏蔽字
            sigprocmask(SIG_SETMASK, &oset, NULL);
            printf("恢复信号屏蔽字\n");
        }
    }

    return 0;
}

运行该程序后,会出现以下情况:

1、初始阶段(前7秒)

  • 程序阻塞 SIGINT(Ctrl+C 触发的信号)。此时按下 Ctrl+C,信号会被标记为未决状态,但不会立即处理。
  • 每秒钟打印一次未决信号集,SIGINT(对应第2位)会显示为 1(若在此期间按过 Ctrl+C)。例如:

2、第7秒后

  • 恢复原始信号屏蔽字(解除对 SIGINT 的阻塞)。
  • 若之前有未决的 SIGINT,此时会立即触发 handler 函数,打印 handler signo:2
  • 后续的 Ctrl+C 会直接触发 handler,未决信号集中 SIGINT 位通常显示 0(除非信号在处理期间再次被发送)。

3、信号处理细节

  • 多次快速按下 Ctrl+C:在阻塞期间,多次信号会被合并,解除阻塞后仅处理一次。
  • 解除阻塞后handler 执行期间,系统默认会暂时阻塞同一信号,因此快速连续按下可能仅触发一次处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南风与鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值