Linux通信之信号(二)

信号集操作函数

内核通过读取未决信号集来判断信号是否应被处理,信号屏蔽字 mask 可以影响未决信号集。而我们可以在应用程序中自定义 set 来改变 mask。以达到屏蔽指定信号的目的。

信号集设定

sigset_t set;         //typedef unsigned long sigset_t;
int sigemptyset(sigset_t *set);  //将某个信号集清零         成功:0;失败:-1
int sigfillset(sigset_t *set);   //将某个信号集置1			成功:0;失败:-1
int sigaddset(sigset_t *set, int signum);	 //将某个信号加入信号集		成功:0;失败:-1
int sigdelset(sigset_t *set, int signum);	 //将某个信号从信号集中删除	成功:0;失败:-1
int sigismember(const sigset_t *set, int signum);	 //判断某个信号是否在信号集中		在集合:1;不在:0

sigset_t 类型的本质是位图。但不应该直接使用位操作,而应该使用上述函数,保证跨系统操作有效。


1. sigprocmask 函数

用来屏蔽信号、解除屏蔽也使用该函数。其本质,读取或修改进程的信号屏蔽字(PCB 中)
【注意】屏蔽信号:只是将信号处理延后执行(延至解除屏蔽);而忽略表示将信号丢弃

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
【参数】
1. set:传入参数,是一个位图,set中哪个位置1,就表示屏蔽哪个信号
2. oldset:传出参数,保存旧的信号屏蔽集
3. how:假设当前的信号屏蔽字为 mask
	- SIG_BLOCK:当 how 设置为此值,set 表示需要屏蔽的信号,相当于 mask = mask | set
	- SIG_UNBLOCK:当 how 设置为此值,set 表示需要屏蔽的信号,相当于 mask = mask & ~set
	- SIG_SETMASK:当 how 设置为此值,set 表示用于替代原始屏蔽集的新屏蔽集,相当于 mask = set。
				   若调用 sigprocmask 解除了对当前若干信号的阻塞,则在 sigprocmask 返回之前,至少将其中一个信号递达。
	

2. sigpending 函数

读取当前进程的未决信号集,不能读取阻塞信号集,但是可以根据未决信号集推出阻塞信号集的状态

int sigpending(sigset_t *set);
【参数】
set:传出参数
【返回值】
成功:0;失败:-1,设置errno

【练习】打印未决信号集

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void print(sigset_t *ped)
{
	int i;
	for(i = 1; i < 32; i++)
	{
		if(sigismember(ped, i) == 1)
		{
			putchar('1');
		}
		else
		{
			putchar('0');
		}
	}
	printf("\n");
}
int main()
{
	sigset_t myset, oldset, ped;
	
	
	sigemptyset(&myset); //现将 myset 中所有信号置0
	sigaddset(&myset, SIGQUIT); //将3号置1
	sigaddset(&myset, SIGTSTP); //将20号置1
	sigprocmask(SIG_BLOCK, &myset, &oldset);
	
	while(1)
	{
		sigpending(&ped); //取出未决信号集
		print(&ped);
		sleep(1);
	}

	return 0;
}

【运行结果】
在这里插入图片描述


信号捕捉

1. signal 函数

注册一个信号捕捉函数:

typedef void(*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

该函数由ANSI定义,由于历史原因在不同版本的 Unix 中可能有不同的行为。因此应该尽量避免使用它,取而代之的是 sigaction 函数
【举个栗子】

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
typedef void (*sighandler_t)(int);
void fun()
{
	printf("---------------catch\n");
}
int main()
{
	sighandler_t handler;
	handler = signal(SIGQUIT, fun); //按下 ctrl+\,捕捉信号
	if(handler == SIG_ERR)
	{
		perror("signal error");
		return -1;
	}
	while(1);
	return 0;
}

【运行结果】每按下 Ctrl + \,都会打印 catch
在这里插入图片描述


2. sigaction 函数

修改信号处理动作(通常在 Linux 用来注册一个信号的捕捉函数)

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
【返回值】
成功:0;失败:-1,设置 errno

struct sigaction {
    void     (*sa_handler)(int);
    void     (*sa_sigaction)(int, siginfo_t *, void *); //不研究
    sigset_t   sa_mask;
    int        sa_flags;
    void     (*sa_restorer)(void); //过时,不用
};
【参数】
1. void (*sa_handler)(int); //捕捉函数
2. sa_mask:用于指定在信号捕捉函数执行期间所屏蔽的信号集
3. sa_flags:

[参数说明]

  • sa_handler
    指定信号捕捉后的处理函数。也可赋值为 SIG_IGN 表示忽略 或 SIG_DEL 表示执行默认动作
  • sa_mask
    调用信号处理函数时,所要屏蔽的信号集合。注意,仅在处理函数调用期间屏蔽生效,是临时性设置
    假设此时正在处理2号信号的信号捕捉函数,这时,又有新的信号到达(比如3,9号信号都到了),这时候会跳出2号信号的捕捉函数,去处理3号和9号的捕捉函数。假设我们用 sa_mask 设置了3号和9号信号屏蔽,那么在处理2号信号的信号捕捉函数期间,3,9号信号到达,那么2号捕捉函数会继续执行,不会跳出来去执行3和9号的捕捉函数。简而言之,sa_mask 的作用就是防止当前正在处理的信号被一些其他信号所打断。
  • sa_flags
    通常设置为 0,表示使用默认属性,在信号处理函数执行期间,自动屏蔽本信号

【举个栗子】写一个捕捉 SIGQUIT 的信号处理函数,在信号处理函数期间,屏蔽 SIGTSTP 信号。

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
typedef void (*sighandler_t)(int);
void fun()
{
	while(1)
	{
		printf("---------------catch\n");
		sleep(1);
	}
}	
int main()
{
	sighandler_t handler;
	sigset_t myset;
	struct sigaction act, oldact;

	sigemptyset(&myset);
	sigaddset(&myset,SIGTSTP);

	act.sa_handler = fun;
	act.sa_flags = 0;
	act.sa_mask = myset;

	
	sigaction(SIGQUIT, &act, &oldact);

	while(1);
	return 0;
}

【运行结果】当 按下 ctrl + \,执行 SIGQUIT 的信号处理函数(循环打印catch),在 SIGQUIT 信号处理函数期间,若按下 ctrl + z,SIGQUIT 的信号处理函数不会退出,会继续执行,但是如果按下 ctrl + c,那么会去执行 ctrl + c的信号处理函数,默认退出进程。
在这里插入图片描述


信号捕捉特性

  1. 进程正常运行时,默认 PCB 中有一个信号屏蔽字,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不由默认信号屏蔽字来决定,而是由 sa_mask 来指定。调用完信号处理函数,在恢复成默认的。
  2. xxx信号捕捉函数执行期间,xxx 信号自动被屏蔽
  3. 阻塞的常规信号不支持排队,产生多次只记录一次。(后32个实时信号支持排队)

内核实现信号捕捉过程

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值