Linux学习笔记19——sigpending 获取当前未决的信号

1,未决

前面提到过,通过修改 信号屏蔽字可以屏蔽信号。当内核发送了一个对当前进程而言已经被屏蔽的信号,且进程不忽略该信号,那么该信号就是未决的。它并不会被捕获,但是信号也没有消失。等到进程不再屏蔽它时,它就会被捕获。

注意,屏蔽与忽略是不同的。

进程屏蔽信号,信号还在,只是没被接收;

进程对信号的动作为忽略,那是进程已经接收到信号了,只是不采取任何动作。

如何获取当前进程的pending进程呢?调用sigpending来实现

#include
int sigpending(sigset_t *set);

2,例子

我们可以通过先屏蔽一个信号,再向进程发送这个信号,最后再取消对信号的屏蔽,来观察pending的效果。

代码可以在上一节的代码基础上修订,我们将main函数修改如下:

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

	//2, 屏蔽SIGUSR1
	sigset_t sigset, oldmask, pendmask;

	//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 修改当前信号屏蔽字
    // 以前的屏蔽字保存进oldmask,便于后面恢复
	if (sigprocmask(SIG_BLOCK, &sigset, &oldmask) < 0)
	{
		printf("can't block SIGUSR1!\n");
		exit(1);
	}

	//3,休眠
	sleep(10); //在休眠期间通过kill发送SIGUSR1

	//4, 获取当前的pending信号
	if(sigpending(&pendmask) < 0)
	{
		printf("pend error!\n");
		exit(1);		
	}

	//5,判断USR1是不是在pendmask里
	if (sigismember(&pendmask, SIGUSR1))
	{
		printf("pending SIGSUR1\n");
	}

	//6,恢复信号屏蔽字
	printf("\nstart to unblock SIGUSR1!\n");
	if (sigprocmask(SIG_SETMASK, &oldmask, NULL))
	{
		printf("can't unblock SIGUSR1!\n");
		exit(1);
	}
	printf("unblock SIGUSR1\n");

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

我们在休眠期间通过kill发送SIGUSR1信号,效果如下:

➜  code g++ -g -W -o study_Linux study_Linux.c
➜  code ./study_Linux &
[1] 136
➜  code kill -USR1 136
➜  code pending SIGSUR1

start to unblock SIGUSR1!
recived SIGUSR, signo = 10
unblock SIGUSR1

我们可以看到,发送USR1后,其对应的signal handler并没有被马上调用,因为该信号被屏蔽了,或者说被pending了。

等我们取消该信号的屏蔽之后,其马上被捕获,出发signal handler。所以被屏蔽的信号并没有消失,只是在等待被捕获。

请注意,在第二次调用sigprocmask时的返回顺序。

第二次调用sigprocmask是取消对信号的屏蔽,取消后SIGUSR1对应的信号处理程序就会被调用。该信号处理程序(sig_usr_new)先返回,打印“recived SIGUSR, signo = 10”,然后sigprocmask才返回,打印“unblock SIGUSR1”。

你可能感兴趣的:(学习笔记,Linux)