进程信号

进程信号

信号概念
  • 信号就是一个软件中断,通知进程发生了某个事件,打断进程当前的操作,去处理这个事件。
  • 信号是多种多样的,并且一个信号对应一个事件,这样才能做到收到一个信号后,知道到底是一个什么样的事件,应该如何处理(但是要保证必须识别这个信号)
信号种类
 kill -l  可以查看所有的信号。
 一共62种信号,1~31 是非可靠信号,34~64是可靠信号。
信号的生命周期

整个流程可以分为 :产生,进程中的注册,进程中的注销,信号的捕捉处理

信号的产生

硬件: ctrl+c ctrl+l ctrl+z
软件: kill命令 kill -signum pid
kill函数 int kill(pid_t pid,int sig); 给pid发送一个sig信号。
int raise(int sig); 给当前调用的进程或线程发送一个sig信号。
abort()没有参数,直接给调用进程发送一个SIGABRT信号,表示程序出现异常,程序退出。
alarm(int seconds) seconds秒后产生时钟信号 。
core dumpe: 核心转储 - 程序异常退出时,保存程序的运行信息,便于事后调试。----默认关闭。

信号在进程中注册

在pcb中有一个未决的信号集合,pending集合, 信号的注册就是指在这个pending集合中标记对应信号数值的二进制为1,

  • 1~31非可靠信号的注册: 若信号还未注册,则注册一下,添加一个sigqueue节点,若已经注册过了,则什么都不做。
  • 34~64可靠信号的注册: 每次注册信号,不管是否已经注册,每次都会添加一个sigqueue节点(信号信息)
信号的注销

删除要处理的信号sigqueue节点,

  • 若信号是非可靠信号,则直接把位图置0(非可靠信号在没有处理之前只会注册一次)
    -若是可靠信号,则删除后,需要判断是否还有相同节点,没有的话才会重置位图为0,
信号的捕捉处理

默认处理 SIG_DFL 默认处理方式
就是用系统原本定义好的默认处理方式
忽略处理 SIG_IGN 忽略处理
就是接受到这种信号时,什么也不做,忽略掉
自定义处理
就是用自己定义的函数来替换原本的默认处理方式.

函数接口:
sighandler_t signal(int signum,sighanler_t handler);
修改信号的回调函数.
signum 为信号,
handler 为回调函数
在这里插入图片描述
sigaction(int signum,struct sigaction *new ,struct sigaction *old);

struct sigaction{
void (*sa_handler) (int signum);
void (*sa_sigaction)(int signum,siginfo_t**siginfo,void * con);
int sa_flag;
sigset_t sa_mask;
}
sa_flag0 使用 (*sa_handler)(int sugnum);回调
sa_falg
SA_SIGINFO 则使用sa_sigaction回调函数

修改信号的整个处理动作,就时把sigaction结构体换为new,把原来的保存在old
下面来看实际代码

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>

void sigcb(int signum){
	printf("recv signum :%d\n",signum);
}


int main(){

	//signal 修改信号的处理方式.
	//SIG_IGN  忽略处理     SIG_DFL   默认处理方式
//	signal(SIGINT,SIG_IGN);   //忽略处理
	signal(SIGINT,sigcb);
	signal(SIGQUIT,sigcb);
	
	while(1){
		printf("hello\n");
		sleep(1);
	}
	return 0;
}
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
void sigcb(int signum){
	printf("recv signum:%d\n",signum);
}


int main(){

	struct sigaction newact;
	struct sigaction oldact;
	newact.sa_handler=sigcb;
	newact.sa_flag=0;
	sigemptyset(&newact.sa_mask);
	//sigaction修改信号的处理动作为newact,原来的动作使用oldact保存
	sigaction(SIGINT,&newact,&oldact);
	
	while(1){
		printf("hello\n");
		sleep(1);
	}
	return 0;

}


自定义信号的捕捉流程:
信号的处理是在程序运行从内核态切换回用户态之前,默认/忽略直接在内核中完成处理,而用户态自定义信号处理方式,则需要返回用户态执行回调函数,完成后返回内核态,最终没有没有信号处理了,再返回程序主流程.
也就是在返回用户态主控流程之前,调用do_signal函数处理未决信号.然后调用sigreturn 返回内核运行,当没有信号等待处理的时候,则返回用户态主控流程.

信号的阻塞

阻止一个信号的抵达,信号依然可以注册,只是暂时不处理
在pcb中一个block位图(信号阻塞集合),凡是添加到这个集合中的信号,都表示需要阻塞,暂时不处理.

int sigprocmask(int how,sigset_t *set,sigset_t *old);
当前要对block集合进行的操作.
SIG_BLOCK 将set集合中的信号添加到block进程阻塞信号集合中, block =block | set
表示阻塞set集合中的信号以及原有的阻塞信号,并且将原有的阻塞信号返回到old集合中.(便于还原);
SIG_UNBLOCK 将set集合中的信号从block集合中移除,将set集合中的信号解除阻塞。
block=block&(~set)
SIG_SETMASK直接将block集合中的信号修改为set集合中的信号,
block=set

接下来我们写个实例

1.先修改指定信号的处理方式SIGINT SIGRTMIN+5 为了当信号到来能够体现到信号的处理。
2.定义一个信号集作为将要阻塞的信号集合 sigset_t set
3.将所有信号都添加到set集合中
4.sigprocmask(SIG_BLOCK,&set,&old);将所有的信号都阻塞起来
5.getchar() 等待一个回车,否则程序就卡在这里。—按下回车则会解除信号的阻塞。
6.sigprocmask(SIG_UNBLOCK,&set,NULL);对set集合的信号解除阻塞
体会信号的阻塞与解除阻塞函数操作;
体会可靠信号与非可靠信号之间的区别;、

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
void sigcb(int signum){
	printf("recv a signal:%d\n",signum);
}


int main(){
	signal(SIGINT,sigcb);
	signal(40,sigcb);	
	//阻塞所有信号,
	sigset_t set,old;
	sigemptyset(&set); //清空信号集合
	sigemptyset(&old); 
	sigfillset(&set);  //将所有的信号都添加到set集合
	//sigaddset(int signum,sigset_t *set) 将指定信号添加到集合。
	sigprocmask(SIG_BLOCK,&set,&old);//阻塞所有信号。
	printf("press enter to continue\n");
	getchar();//在按下回车之前,程序卡在这里
	//按下回车后,然后在解除阻塞
	sigprocmask(SIG_UNBLOCK,&set,NULL);//解除阻塞。
	return 0;
}

在所有的信号中,有两个信号不可被阻塞,不能被自定义修改处理方式,也不能被忽略,这两个信号SIGKILL 9号信号
SIGSTOP 19信号不能不能阻塞。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值