Linux学习笔记22——sigsuspend 让指定的信号无法唤醒进程

1,由来

让指定的信号无法唤醒进程貌似很简单,只要先设置屏蔽字屏蔽指定的信号,再pause就可以了。以后只要接收到信号,切该信号不是指定的信号就可以结束 pause。但是,这种做法是分两步做的,而信号可以发生在任何时候。如果在设置屏蔽字与pause之间就触发了那个指定的信号怎么办??

所以我们需要一个原子操作的函数来实现这一功能。这就是sigsuspend.

int sigsuspend(const sigset_t* sigmask);

注意:这个函数在正确返回是返回-1.。。。。。

sigmask指定的信号将被屏蔽,无法唤醒进程;而其他信号被捕捉到并从信号处理程序返回后,将唤醒进程,哪怕是之前被屏蔽的信号。

2,例子

int main(){
	//10.16 sigsuapend
	sigset_t newmask, oldmask, waitmask;

	//1,程序开始处打印屏蔽字,应该是什么都没有
	pr_mask("program start: ");

	//2,注册3个信号
	if (signal(SIGINT, sig_int) == SIG_ERR)
		err_sys("signal error!");

	if (signal(SIGUSR1, sig_usr) == SIG_ERR)
		err_sys("signal error!");

	if (signal(SIGUSR2, sig_usr_new2) == SIG_ERR)
		err_sys("signal error!");

	//3,准备屏蔽字
	sigemptyset(&waitmask); //sigsuspend时的屏蔽字
	sigaddset(&waitmask, SIGUSR2);
	sigemptyset(&newmask);  //sigsuspend之前的屏蔽字
	sigaddset(&newmask,SIGUSR1);

	//4,屏蔽信号SIGUSR1
	if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
		err_sys("SIG_BLOCK error!");

	//5,从这里到sigsuspend调用之间都是安全区
	//   打印安全区的屏蔽字
	pr_mask("in critical region: ");

	//6,设置等待,仅仅waitmask指定的信号不能让其退出等待,其他信号都可以
	if(sigsuspend(&waitmask) != -1)
		err_sys("sigsuspend error!");

	//7,上一步的函数在接收到信号后返回,打印返回后的屏蔽字
	pr_mask("after return from sigsuspend:  ");

	//8,恢复屏蔽字
	if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
		err_sys("SIG_SETMASK error!");

	//9,打印回复后的屏蔽字
	pr_mask("program exit: ");

	exit(0);	
}

//针对SIGUSR1的信号处理程序
static void sig_usr(int signo) {
    printf("received SIGUSR1 %d,, signo =\n", signo);  
	pr_mask("in sig_usr: "); 
}

void sig_usr_new2(int signo)
{
	printf("recived SIGUSR2, signo = %d\n",signo);
	pr_mask("in sig_usr_new2: ");
}

void sig_int(int signo)
{
	pr_mask("\nin sig_int: ");
}

void err_sys(const char *str)
{
	printf("%s\n",str);
	exit(1);
}

我们先屏蔽USR1,再通过sigsuspend屏蔽USR2,看看这两者有啥不同。

执行效果:

➜  code g++ -g -W -o study_Linux study_Linux.c
➜  code ./study_Linux &
[1] 559
zsh: nice(5) failed: operation not permitted
program start:
in critical region:     SIGUSR1
➜  code
➜  code kill -USR2 559
➜  code
➜  code kill -USR1 559
received SIGUSR1 10
in sig_usr:     SIGUSR1 SIGUSR2
recived SIGUSR2, signo = 12
in sig_usr_new2:        SIGUSR1 SIGUSR2
after return from sigsuspend:   SIGUSR1
program exit:
[1]  + 559 done       ./study_Linux
➜  code 

我们在调用sigsuspend之前已经屏蔽了SIGUSR1,这一点在in critical region的打印中可以看到;

接下来,由于sigsuspend的执行,程序挂起,等待信号。

我们先向其发送SIGUSR2信号,由于这个信号被sigsuspend指定为该屏蔽的信号,所以我们看到什么都没发生,程序继续挂起;

接下来我们向其发送SIGUSR1信号,虽然这个信号之前是被屏蔽的,但是现在它却被正确地捕获并执行了信号处理程序。

比较诡异的是,我们在信号处理程序中打印当前的屏蔽字,赫然发现SIGUSR1和SIGUSR2都是被屏蔽的?!!

既然这两个都是被屏蔽的,怎么现在我们还接收到了 SIGUSR1 ?!并且之前还接收不到SIGUSR2.。。。。

貌似通过sigprocmask和sigsuspend两种方式屏蔽信号,待遇是不一样的。在由sigsuspend导致的等待期间,我们是只认由sigsuspend指定的信号的。其他的信号哪怕在信号屏蔽字里也不屏蔽!真的很好奇sigsuspend是怎么实现的,居然可以无视进程的信号屏蔽字。

 

继续。

在从SIGUSR1的信号处理程序返回后,进程马上调用了SIGUSR2的信号处理程序。。。

还记得我们是先发送SIGUSR2,再发送SIGUSR1吧。之前SIGUSR2被屏蔽了,貌似此时已经解除了封印。

在SIGUSR2的信号处理程序中打印出的信号屏蔽字依然是SIGUSR2和SIGUSR1都在。

 

在这两个信号都处理完之后,进程终于从sigsuspend返回了。返回后进程的屏蔽字会发生变化,它会恢复sigsuspend调用前的屏蔽字,我们看到此时屏蔽字里只剩下SIGUSR1了。

最后一步,再把SIGUSR1的屏蔽也恢复掉。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值