linux信号阻塞与未决

执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。

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

信号在内核中的表示可以看作是这样的:


1PCB进程控制块中函数有信号屏蔽状态字(block)信号未决状态字(pending)还有是否忽略标志(或是信号处理函数)block状态字、pending状态字 64bit

2信号屏蔽状态字(block),1代表阻塞、0代表不阻塞;信号未决状态字(pending)的1代表未决,0代表信号可以抵达了;它们都是每一个bit代表一个信号,比如,bit0代表信号SIGHUP;

3:比如向进程发送SIGINT,内核首先判断信号屏蔽状态字是否阻塞,如果该信号被设为为了阻塞的,那么信号未决状态字(pending)相应位制成1;若该信号阻塞解除,信号未决状态字(pending)相应位制成0;表示信号此时可以抵达了,也就是可以接收该信号了。

 4屏蔽状态字用户可以读写,未决状态字用户只能读;这是信号设计机制。

API函数:

信号集操作函数,对状态字进行操作(屏蔽状态字和未决状态字):

#include <signal.h>  
int sigemptyset(sigset_t *set);//将信号集清空,共64bits  
int sigfillset(sigset_t *set);//将信号集置1  
int sigaddset(sigset_t *set, int signum);//将signum对应的位置为1  
int sigdelset(sigset_t *set, int signum);//将signum对应的位置为0  
int sigismember(const sigset_t *set, int signum);//判断signum是否在该信号集合中,如果集合中该位为1,则返回1,表示位于在集合中  
还有一个函数可以读取更改屏蔽状态字的API函数
#include <signal.h>  
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);  

参数how有下面三种取值:
SIG_BLOCK:  将参数set指向的信号集中设置的信号添加到现在的屏蔽状态字中,设置为阻塞;
SIG_UNBLOCK:将参数set指向的信号集中设置的信号添加到现在的屏蔽状态字中,设置为非阻塞, 也就是解除阻塞;
SIG_SETMASK:将参数set指向的信号集直接覆盖现在的屏蔽状态字的值;
如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。
若成功则为0,若出错则为-1

还有一个函数可以读取未决状态字(pending)信息 
#include <signal.h>  
int sigpending(sigset_t *set);  
实例解析:
刚开始设置SIGINT信号为阻塞信号,当按下Ctrl+c发送中断信号SIGINT(值为2,所以后来第二位被置1)之前,未决状态字的所有位都是0,因为此时没有未抵达的信号;
当发送SIGINT信号后,因为该信号是阻塞的,所以未决状态字将第二位置为了1,表示该信号在这里阻塞了;当我按下Ctrl+\发送SIGQUIT信号后,又将SIGINT信号设置为了非阻塞的;此时可以看到未决状态字的所有位都变为了0;并且也收到了刚才阻塞的SIGINT信号;
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

void handler(int num)
{
	if (num == SIGINT)
	{
		printf("刚才已经收到了中断信号sigquit,取消了阻塞..\n");

	}
	else if (num == SIGQUIT)
	{
		//将SIGINT信号设置为非阻塞
		sigset_t un_bset;
		sigemptyset(&un_bset);
		sigaddset(&un_bset, SIGINT);
		sigprocmask(SIG_UNBLOCK, &un_bset, NULL);
	}
}

void print_pending(sigset_t *pset)
{
	int i = 0;
	printf("未决状态字(64位):");
	for (i = 1; i <= 64; i++)
	{
		if (sigismember(pset, i))
			printf("1");
		else
			printf("0");
		if (i % 8 == 0)
		{
			printf(" ");
		}
	}
	printf("\n");
}

int main()
{
	sigset_t bset;
	sigset_t pset;


	//设置SIGINT信号
	sigemptyset(&bset);
	sigaddset(&bset, SIGINT);

	signal(SIGINT, handler);
	signal(SIGQUIT, handler);

	//将SIGINT信号设置为阻塞的
	sigprocmask(SIG_BLOCK, &bset, NULL);

	while (1)
	{
		//得到未决状态字
		sigpending(&pset);

		print_pending(&pset);
		sleep(1);
	}
	exit(0);
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值