Linux——信号知识归纳(中)

目录

一.信号与硬件异常

二.阻塞信号和信号结构

(一).信号状态

(二).信号结构

①pending表

②block表

③handler表

(三).信号处理过程

(四).阻塞与忽略的区别

(五).不可阻塞和自定义的信号

三.信号函数

①sigpending

②sigprocmask

③sigemptyset

④sigfillset

⑤sigaddset

⑥sigdelset

⑦sigismember

⑧使用示例


一.信号与硬件异常

硬件产生异常并使程序崩溃的方式有很多,比如除0错误、空指针、数组越界等。

大致上,当硬件产生异常后,会“汇报”给操作系统,再由操作系统发送相关信号给进程,促使进程异常退出。

以除0错误为例,当cpu检测到除0后,其中状态寄存器会标记异常,操作系统识别到该寄存器标记了异常后,发送信号给当前进程,进而进程崩溃退出。

再比如空指针问题,当虚拟地址为空时,页表通过MMU(硬件)映射时会出错,MMU内部寄存器会标记异常,操作系统识别后发送信号给进程,进程崩溃退出。

二.阻塞信号和信号结构

(一).信号状态

信号在发送过程中有三种状态:未决、递达、阻塞

状态含义
信号未决信号产生后,进程接收但未执行具体方法
信号递达执行信号方法的状态或正在处理信号
信号阻塞进程收到信号,但不允许递达,即不允许处理信号

如果某信号处于阻塞态,那么该信号将无法调用对应的信号函数。

(二).信号结构

首先,我们需要知道的是,信号在操作系统中以位图的形式记录,普通信号是1 - 31,正好可以使用位图对照,0代表进程此时没收到该信号,1代表收到该信号。

实际上,linux的信号有三个信号表构成,即pending表、block表、handler表

这三个表属于进程PCB结构体,记录在task_struct中。

①pending表

该表本质上是一个位图结构,记录进程是否收到该位对应的信号。0代表没有收到,1代表收到。

②block表

该表也是位图结构,每一位记载该信号是否阻塞,0代表未阻塞,1代表阻塞。

③handler表

该表是函数指针数组,数组每一个下标对应一个信号,每个下标对应的指针指向该信号的处理函数。

SIG_IGN表示处理方式为忽略。

SIG_DFL表示处理方式为默认。

比如2号信号使用默认函数可以表示为:

signal(SIGINT, SIG_IGN);

(三).信号处理过程

(四).阻塞与忽略的区别

阻塞是进程接收信号后,“故意”不执行方法。

忽略是进行接收信号后,执行了方法,但方法是忽略。

本质上,阻塞是将block表该位置1;忽略的该位为0,在handler表中记载的是SIG_IGN。

(五).不可阻塞和自定义的信号

9号信号SIGKILL、18号信号SIGCONT、19号信号SIGSTOP不可被阻塞和自定义。

换句话说,即便是手动添加阻塞信号或自定义处理方法也是无效的,依旧执行默认的方法。

三.信号函数

①sigpending

用于获取当前进程的pending表。

 操作系统中定义了sigset_t类型的数据,按位图的形式保存信号,即信号集。 

 第一个参数是输出型参数,通过该函数获得当前进程的pending位图。

返回值0代表获取成功,-1代表获取失败。

②sigprocmask

用于改变阻塞信号

 第一个参数有三个可选项:

选项含义操作
SIG_BLOCKset中所有置1的都设置成阻塞block = block | set
SIG_UNBLOCKset中所有置1的都设置成非阻塞block = block & ~set
SIG_SETMASK进程block位图表与set表一致block = set

第二个参数是输入型参数,用于确定哪些位阻塞/解除阻塞

第三个参数是输出型参数,获取旧的block位图表。

返回值含义与sigpending一致。

③sigemptyset

用于将信号集全部置0

参数为输出型参数,set内各位将置为0。

返回值含义与sigpending一致。

④sigfillset

用于将信号集全部置1

参数为输出型参数,set内各位将置为1。

返回值含义与sigpending一致。

⑤sigaddset

用于将信号集某一位设置为1

 第一个参数为输出型参数,set中指定位将置1。

第二个参数为指定的信号值。

返回值含义与sigpending一致。

⑥sigdelset

用于将信号集某一位设置为0

 参数和返回值含义与sigdelset相同,唯一不同就是该位设置为0。

⑦sigismember

用于确定信号集特定位的数值

 第一个参数为输入型参数,输入的待查看的信号集。

第二个参数为指定的信号值

返回值1代表该位为1,0代表该位为0,-1代表错误。

⑧使用示例

int main(){
    sigset_t block, oldBlock;
    //将1 - 31号信号全部阻塞
    for(int i = 1; i <= 31; i++){
        sigaddset(&block, i);
    }
    int n = sigprocmask(SIG_BLOCK, &block, &oldBlock);
    assert(n == 0);
    //循环打印当前进程的pending位图
    while(true){
        sleep(1);
        sigset_t set;
        sigpending(&set);//获取pending位图
        //循环判断1 - 31位是0还是1并打印
        for(int i = 1; i <= 32; i++){
            if(sigismember(&set, i)) cout << "1";
            else cout << "0";
        }
        cout << endl;
    }

    return 0;
}

Software is like sex: it's better when it's free——Linus Torvalds


如有错误,敬请斧正

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

就要 宅在家

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

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

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

打赏作者

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

抵扣说明:

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

余额充值