Linux入门:信号(二)——阻塞信号

       实际执行信号的处理动作称为信号递达(Delivery)。

       信号从产生到递达之间的状态,称为信号未决(Pending)。

       进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程接触对此信号的阻塞,才执行递达的操作。(阻塞和忽略不同,只有信号阻塞就不会递达,而忽略是在信号递达之后可选的一种处理动作。而一个被阻塞的信号想要递达,需要先Pending再解除阻塞。)

       每个信号都有两个标志位分别表示阻塞和未决,还有一个函数指针表示处理动作。信号产生时,内核在进程的PCB设置该信号的未决标志,直到信号递达才清除该标志。

      如果进程在解除对某信号的阻塞之前这种信号产生了多次,将如何处理?POSIX.1允许系统递达信号一次或多次。在Linux中:常规信号在递达之前产生多次只计一次,实时信号在递达之前产生多次可以依次放在一个队列里。对于常规信号,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集。


信号的阻塞就是让系统暂时保留信号待以后发送。由于另外有办法让系统忽略信号,所以一般情况下信号的阻塞只是暂时的,只是为了防止信号打断敏感的操作。当需要修改某些全局变量时,可以通过sigprocmask()函数阻塞处理函数中也使用该变量的信号。在某些信号处理函数中,为了防止同类信号的到来,可以使用sigaction()函数的sa_mask阻塞特定的信号。

    阻塞信号的作用:使用函数sigprocmask()阻塞信号的传递,只是延迟信号的到达。信号会在解除阻塞后继续传递。这种情况往往需要在信号程序和其它程序共享全局变量时,如果全局变量的类型不是sig_atomic_t类型,当一部分程序恰好读、写到变量过程中,产生某个信号,而信号程序里会改变该变量,那么就会产生混乱。为了避免这种混乱,提供程序的可靠性,你必须在操作这类变量前阻塞信号,操作完成后恢复信号的传递。


信号集操作函数:



程序:
#include <stdio.h>
#include <signal.h>

void handler(int sig)
{
	printf("sig = %d\n", sig);
}

void show_pending(sigset_t *pending)
{
	int i = 1;
	for(i=1; i<=31; i++)
	{
		//判断指定信号是否在目标信号集中
		if(sigismember(pending, i))
		{
			printf("1");
		}
		else
		{
			printf("0");
		}
	}
	printf("\n");
}

int main()
{
	//捕捉2号信号
	signal(2, handler);
	sigset_t block;
	sigset_t oldblock;
	sigset_t pending;
	sigemptyset(&block);
	sigemptyset(&oldblock);

	//设置阻塞信号集,阻塞2号信号
	sigaddset(&block, 2);
	sigprocmask(SIG_SETMASK, &block, &oldblock);

	int count = 0;
	while(1)
	{
		//获取未决信号集
		sigpending(&pending);
		show_pending(&pending);
		sleep(1);
		count++;
		if(count == 10)
		{
			//解除对当前未决信号的阻塞
			sigprocmask(SIG_SETMASK, &oldblock, NULL);
		}
	}
	return 0;
}
运行结果:


程序运行时,每秒钟把各信号的未决状态打印一遍,由于我们阻塞了SIGINT信号,则使SIGINT信号(Ctrl-C)处于未决状态,按Ctrl-Z则可以终止程序.

猜你喜欢

转载自blog.csdn.net/if9600/article/details/72916528
今日推荐