Linux学习笔记18——sigprocmask 信号屏蔽字

1,信号集

我们可以将多个信号编成一个集合,对集合内的信号进行同样的操作(比如忽略一个信号集内的所有信号)。信号集的数据类型为sigset_t。还有一些与之相关的函数用于初始化信号集、向信号集中添加、删除信号,以及判断某个信号是否在信号集内。

原型如下:

#include<signal.h>
int sigemptyset(sigset_t *set); //将set指向的信号集初始化为不包含任何信号
int sigfillset(sigset_t *set);  //将set指向的信号集初始化为包含所有信号
int sigaddset(sigset_t *set, int signo);//向信号集添加信号signo
int sigdelset(sigset_t *set, int signo);//向信号集删除信号signo
int sigismember(const sigset_t *set, int signo);//判断信号signo是否在信号集中

信号集在使用前一定要用sigemptyset或sigfillset初始化,不能指望于C语言的默认初始化(可惜了,没有C++里的默认构造函数)。

2,sigprocmask

现在我们可以尝试屏蔽掉一个信号集里的所有信号了。

一个进程是否屏蔽某个信号是由该进程的信号屏蔽字决定的。信号屏蔽字是一个信号集,其包含的信号都会被阻塞而不能递送给这个进程。而sigprocmask就是用来修改进程的信号屏蔽字的,因此它可以屏蔽某个信号会对某个已经屏蔽的信号解除屏蔽。

其原型如下:

int sigprocmask(int how, const sigset_t *restrict set, const sigset * restrict oset);

其中,

restrict是C99的关键字,代表这两个指针不会指向同一个对象;

oset若不为空,则会获得修改前的信号屏蔽字;

set是将会对当前信号屏蔽字产生影响的信号集。可以用set对当前信号屏蔽字进行或运算、且运算或复制运算。具体是哪种运算,就由how决定。

具体如下:

how == SIG_BLOCK,或运算,与当前屏蔽字取并集,set中指定的信号都会被屏蔽;

how==SIG_UNBLOCK,取反再且运算,set的补集与当前屏蔽字取交集,set中指定的信号都会被解除屏蔽;

how==SETMASK,赋值运算,新的信号屏蔽字被设置为set。

如果set为空呢?这时不会对信号屏蔽字产生任何影响,how的值也就无所谓。

通常,想获取当前信号屏蔽字的时候,就将set设为空,然后通过oset来获取。

sigprocmask(0, NULL, &oset);

这样调用即可。

3,例子

我们设计一段代码,她让当前进程屏蔽SIG_USR1,而不屏蔽SIG_USR2.

然后,我们用kill命令分别向这个进程发送这两个信号,观察现象。

代码如下:

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

void sig_usr_new(int signo);

int main(){
	//1,注册信号
	if(signal(SIGUSR1, sig_usr_new) == SIG_ERR)
	{
		printf("can't catch SIGUSR1 !\n");
		exit(1);
	}

	if(signal(SIGUSR2, sig_usr_new) == SIG_ERR)
	{
		printf("can't catch SIGUSR2 !\n");
		exit(1);
	}

	//2, 修改信号屏蔽字
	sigset_t sigset;

	//2.1 初始化sigset
	if (sigemptyset(&sigset) < 0)
	{
		printf("sigemptyset error !\n");
		exit(1);
	}

	//2.2 添加要屏蔽的信号
	if (sigaddset(&sigset, SIGUSR1) < 0)
	{
		printf("add SIGUSR1 error!\n");
		exit(1);
	}

	//2.3 修改当前信号屏蔽字
	if (sigprocmask(SIG_BLOCK, &sigset, NULL) < 0)
	{
		printf("can't block SIGUSR1!\n");
		exit(1);
	}

	//3,死循环,为了防止进程退出
	while(1){
		pause();
	}
}

void sig_usr_new(int signo)
{
	printf("recived SIGUSR, signo = %d\n",signo);
}

我们给当前进程注册了两个信号SIG_USR1和SIG_USR2,这两个信号还绑定到同一个信号处理函数。所以如果它们被触发,会调用同样的函数。然后,我们屏蔽了其中一个信号,观察效果。

➜  code ./study_Linux&
[1] 83
zsh: nice(5) failed: operation not permitted
➜  code kill -USR1 83 //发送SIGUSR1,没有任何函数被调用
➜  code kill -USR2 83 //发送SIGUSR1,有函数被调用
recived SIGUSR, signo = 12
➜  code kill 83
[1]  + 83 terminated  ./study_Linux
➜  code ps
  PID TTY          TIME CMD
    4 tty1     00:00:01 zsh
  105 tty1     00:00:00 ps

注意,有两个信号是无法被屏蔽的,它们死SIGKILL 和SIGSTOP。

如果连这两个信号都能屏蔽,那进程岂不是有可能成为一个怎么都停不下来的流氓进程?!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值