进程信号

什么是进程信号?

进程信号是一种事件通知机制,属于软件中断

信号的作用:发生某事件时,打断进程当前操作,转而去处理这个事件

通俗点的栗子:

假设你正在学习,没有突发事件你不会停止学习。(此时你就是一个进程)此时你的母上大人做好了午饭,跑来叫你吃饭(吃饭信号)。然后你就去吃饭了,不学习了,吃完饭又回来学习(处理完信号回来继续作业)

请注意!信号与信号量完全不是同一个概念!

信号量是进程间通信(IPC)的方式之一,而信号是一种事件通知机制
在这里插入图片描述

信号的种类

在linux中使用kill -l可以查看所有信号,如下(共有62种):
在这里插入图片描述
在上图中的信号中:
1-31号信号属于非可靠信号
34-64号信号属于可靠信号

有小伙伴不清楚什么是可靠信号/不可靠信号,可以移步此处详细了解下:可靠信号与不可靠信号

信号的产生

产生方式列举解释
硬件产生ctrl+c中断,即2号信号SIGINT
ctrl+\退出,即3号信号SIGQUIT
ctrl+z中止,即20号信号SIGTSTP
软件产生kill命令kill -signum pid:给pid号进程发送序号为signum的信号,默认15号终止信号
kill()接口发送指定信号
raise()接口给调用进程本身发送一个指定信号
alarm()接口设置一个定时器
abort()接口给进城发送一个SIGABRT信号

信号的生命周期:产生->注册->注销->处理 + 阻塞
之所以先注销再处理的原因:防止信号被重复处理

信号的注册

未决信号集合中标记信号+添加信号的信息节点

在pcb中有个未决信号集合(还没有被处理的信号的集合)【使用位图实现】
非可靠信号:若信号已经注册,则不作任何操作
可靠信号:无论信号是否注册,都会进行注册

信号的注销

在pcb中删除信号信息节点,重置位图

非可靠信号:删除节点信息,直接位图重置
可靠信号:删除信息节点之后,确定没有相同节点才会重置位图

信号的处理

即信号的递达——执行信号的处理回调函数

sighandler_t signal(int signum,sighandler_t handler);
		signum:信号值  handler:信号要新指定的处理方式
		handler:SIG_DEL-默认; SIG_IGN-忽略;自定义
			     类型->typedef void*(sighandler_t(int);
返回值:成功返回信号原来的处理方式;失败返回-1(SIG_ERR)

信号的阻塞

阻塞一个信号表示收到这个信号后暂时不处理,直到解除阻塞之后进行处理

在pcb中,有一个信号阻塞集合,在这个集合中标记哪个信号则表示阻塞哪个信号

int sigprocmask(int how,sigset_t *set,sigset_t *oldset);
	how:要对信号阻塞集合进行的操作类型
		SIG_BLOCK:将set集合中的信号添加到阻塞集合中
		SIG_UNBLOCK:从阻塞集合中移出set集合中的信号
		SIG_SETMAS:将阻塞集合中的信号设置为阻塞集合的信号
	oldset:用于保存修改前阻塞集合的信息,不使用置空即可
返回值:成功0,失败-1
int sigemptyset(sigset* set);清空set集合
int sigfillset(sigset* set);将所有信号添加进set集合
int sigaddset(sigset* set,int signum);将指定信号添加至set集合
int sigdelset(sigset* set,int signum);从集合中移除指定信号
int sigmember(sigset* set,int signum);判断信号是否在集合中

在所有信号中,有两个信号比较特殊:
SIGKILL-9/SIGSTOP-19不会被阻塞,处理方式也不会被修改

1.使用sigprocmask()阻塞2号信号和40号信号, 分别给进程发送5次2号信号和5次40号信号,观察结果

code
#include <stdio.h>    
#include <unistd.h>    
#include <signal.h>    
#include <stdlib.h>    
    
void signo(int signo){    
    printf("接收到[%d]信号\n",signo);    
}    
int main(){    
    sigset_t set;//定义信号集合    
    sigemptyset(&set);//清空信号集合    
    sigaddset(&set,2);//将2号信号加入集合    
    sigaddset(&set,40);    
    sigprocmask(SIG_BLOCK,&set,NULL);//将信号集合加入阻塞集合    
    signal(2,signo);   //设置信号2的处理方式 
    signal(40,signo);    
    int cnt = 5;    
    while(cnt--)    //kill()产生信号
        kill(getpid(),2);    
    cnt = 5;    
    while(cnt--)    
        kill(getpid(),40);    
    sigprocmask(SIG_UNBLOCK,&set,NULL);//将信号集合移出阻塞集合    
    return 0;                                                                                   
}    

在这里插入图片描述
由结果我们可以轻易验证可靠信号与不可靠信号在注册部分的差异
a.可靠信号产生几次,注册几次
b.不可靠信号,未决集合中存在,只会注册一次,产生再多也只会处理一次

2.使用signal函数自定义SIGINT信号的处理方式

code
#include <stdio.h>    
#include <stdlib.h>    
#include <unistd.h>    
#include <signal.h>    
void sigcb(int signo){    
    printf("接收到[%d]号信号!\n",signo);    
}    
int main(){    
    signal(2,sigcb);    
    while(1){    
        printf("main runing!\n");    
        sleep(1);    
    }    
    return 0;                                                                                       
}    

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值