捕捉信号的处理

文章目录


信号捕捉

信号捕捉是进程从内核态返回用户态时会对信号进行检测处理。
在这里插入图片描述
如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。由于信号处理函数的代码是在用户空间的,处理过程比较复杂,举例如下: 用户程序注册了SIGQUIT信号的处理函数sighandler。 当前正在执行main函数,这时发生中断或异常切换到内核态。 在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGQUIT递达。 内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函 数,sighandler和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是 两个独立的控制流程。 sighandler函数返回后自动执行特殊的系统调用sigreturn再次进入内核态。 如果没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行了。

捕捉信号用sigaction和signal函数进行对信号进行捕捉处理,而在调用捕捉之后进程pending位图对应比特位编号会由1变为0,它是说明时候由1变为0,是在信号捕捉之前
在这里插入图片描述
sigaction可以检测和处理与指定信号相关联的动作。调用成功则返回0,出错则返回- 1。参数signo是指定信号的编号。而act和oldact是结构体类型指针,是一种结构体,若act指针非空,则根据act修改该信号的处理动作,输入型参数。若oact指针非空,则通过oact传
出该信号原来的处理动作,输出型参数。act和oact指向sigaction结构体:
在这里插入图片描述
在这里插入图片描述

结构体中包含对信号的处理方法,以及对信号的屏蔽设置。
将sa_handler赋值为常数SIG_IGN传给sigaction表示忽略信号,赋值为常数SIG_DFL表示执行系统默认动
作,赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册了一个信号处理函 数,该函数返回
值为void,可以带一个int参数,通过参数可以得知当前信号的编号,这样就可以用同一个函数处理多种信
号。显然,这也是一个回调函数,不是被main函数调用,而是被系统所调用。sa_handler为处理对应信号的处理动作。
sa_mask是对信号集做屏蔽的字段就对应进程内核中的block表。
运行一个进程然后让他对2号信号进行捕捉

#include <iostream>
#include <cstring>
#include <ctime>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;


void PrintPending()
{
    sigset_t set;
    sigpending(&set);

    for (int signo = 1; signo <= 31; signo++)
    {
        if (sigismember(&set, signo))
            cout << "1";
        else
            cout << "0";
    }
    cout << "\n";
}

void handler(int signo)
{
    cout << "catch a signal, signal number : " << signo << endl;
    while (true)
    {
        PrintPending();
        sleep(1);
    }
}

int main()
{
    //先定义两个结构体对象
     struct sigaction act, oact;
     //对两个结构体对象做清零初始化
    memset(&act, 0, sizeof(act));
    memset(&oact, 0, sizeof(oact));

    //然后对信号集做初始化,sa_mask是信号集和中的block信号集
    sigemptyset(&act.sa_mask);
    act.sa_handler = handler; // SIG_IGN SIG_DFL,一般是默认但是在这里设置为了自定义方法

    sigaction(2, &act, &oact);//对2号信号进行捕捉,然后执行对象中方法act是输入型参数,oact为输出型参数

    while (true)
    {
        cout << "I am a process: " << getpid() << endl;
        sleep(1);
    }

    return 0;
}

在这里插入图片描述
对信号处理并且要将为位图上对应信号编号位比特位由1清零,捕捉时获取pending位图,通过实验发现由1清零这个动作是在捕捉之前对pending进行清零操作。并且此时处于信号捕捉状态若是操作系统再对进程发送信号,那么这个进程会不会再陷入这个捕捉信号处理动作中?不会,操作系统不能让一个进程对于一个信号一直处于捕捉状态,防止信号不断递达,进程会自动屏蔽这个信号,就是通过sa_mask实现,它会自动将当前捕捉的这个信号添加到进程block表中,然后当进程再次收到同样的信号时,只会在pending中保存而不会被递达,让这个信号阻塞!
在这里插入图片描述
对于当前信号屏蔽是内核自动做的,因为他不会目睹你一直在调度这个捕捉函数,而当执行完捕捉函数时,返回会自动将这个屏蔽信号解除屏蔽。所以也能得出信号在处理时不能重复调用。正在处理2号信号2号信号会防止重复捕捉,若是我在处理2号信号时,想让进程对其他信号进行屏蔽,当其他信号到来时对其他信号屏蔽,就可以将想要屏蔽的信号添加到sa_mask中,就可以在处理当前信号时让进程对其他信号做屏蔽
对1、3、4号信号做屏蔽,然后再向进程发送这几个信号时,不会处理对应信号动作,而是对其进行屏蔽,然后在pending位图中保存起来
在这里插入图片描述

当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么 它会被阻塞到当前处理结束为止。 如果在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。 对信号的捕捉可以使其对其他信号不做出响应。

  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值