linux信号集与信号掩码-保护信号处理程序,确保进程正确运行


在Linux环境下,当进程收到信号时,如何优雅地处理并确保程序的正常运行?这就需要借助信号集和信号掩码的功能。本文将为你揭开信号集和信号掩码的神秘面纱,并通过生动的代码示例,让你彻底掌握在C++程序中使用它们的技巧。


一、信号集:表示信号的数据结构

信号集(signal set)是一种用于表示进程当前阻塞了哪些信号的数据结构,它本质上是一个数组 bitmap,使用sigset_t结构体来表示。每一种信号对应一个位,如果该位被置位(值为1),则表示该信号被阻塞,否则(值为0)表示未被阻塞。


在这里插入图片描述


我们可以使用以下函数来操作信号集:

  • sigemptyset(&set): 将set中所有位清零,即不阻塞任何信号
  • sigfillset(&set): 将set中所有位置1,即阻塞全部信号
  • sigaddset(&set, sig): 将信号sig对应的位置1,即阻塞该信号
  • sigdelset(&set, sig): 将信号sig对应的位清零,即解除对该信号的阻塞
  • sigismember(&set, sig): 检查信号sig是否被set阻塞

示例代码:

#include <signal.h>
#include <iostream>

int main() {
    sigset_t set;
    
    // 初始化为空集
    sigemptyset(&set); 
    
    // 阻塞所有信号的传递
    sigset_t newset;
	  sigfillset(&newset);
    
    // 添加SIGINT(Ctrl+C)信号
    sigaddset(&set, SIGINT);
    
    // 检查SIGINT是否在集合中
    if (sigismember(&set, SIGINT)) {
        std::cout << "SIGINT is blocked" << std::endl;
    }
    
    // 移除SIGINT
    sigdelset(&set, SIGINT);
    
    return 0;
}

二、信号掩码:阻塞信号的机制


1、信号掩码(signal mask)

信号掩码(signal mask)是Linux内核为每个进程维护的一个信号集,用于暂时阻塞该进程接收某些信号。除了SIGKILL和SIGSTOP这两个特殊信号外,其他信号都可以被阻塞。

内核会为每一个进程都维护一个信号掩码,也就是一组信号,阻塞其针对该进程的传递,直到进程从信号掩码中将该信号移除。

我们可以通过sigprocmask系统调用来修改进程的当前信号掩码:

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
  • how 参数指定如何修改掩码
    • SIG_BLOCK: 将set指向的信号集并入当前掩码
    • SIG_UNBLOCK: 将set指向的信号集从当前掩码中移除
    • SIG_SETMASK: 使用set指向的信号集作为新的信号掩码
  • oldset 用于保存修改前的信号掩码,如果不需要可设为NULL

例如,阻塞SIGINT(Ctrl+C)信号:

#include <signal.h>
#include <iostream>

int main() {
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    
    // 阻塞SIGINT信号
    sigprocmask(SIG_BLOCK, &set, NULL);
    
    // 此时按下Ctrl+C将不会终止程序
    while (true) {
        std::cout << "Program running..." << std::endl;
        sleep(1);
    }
    
    return 0;
}

2、系统的默认行为

前面我们提到过,当前进程正在调用
SIGX
的信号处理函数,那么紧接着而来的
SIGX
信号将会被阻塞,直到上一个信号处理函数结束,这一现象我们可以用一个简单的例子证明 :

void handler(int signum)
{ 
  printf("Got a SIGINT\n"); 
  sigset_t currentset; 
  sigprocmask(SIG_BLOCK,NULL,&currentset); 
  int res=sigismember(&currentset,SIGINT);
  printf("SIGINT is blocked ?:%d\n",res); 
}

我们用
SIGINT
作为捕获信号,当我们键入
Ctrl-C 时,将会发现 SIGINT
信号的确是在当前进程的信号掩码中。

引发对处理器程序调用的信号将自动添加到进程信号掩码中。这意味着,当正在执行处理器程序时,如果同一个信号 实例第二次抵达,信号处理器程序将不会递归中断自己。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

w风雨无阻w

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

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

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

打赏作者

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

抵扣说明:

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

余额充值