信号
-
信号是什么?
- 是一个软件中断,通知进程发生了某个事件,打断当前操作去处理这个事件
- 信号有很多种类,每个信号代表一个事件
-
信号种类
- 62种
- 1~31:非实时信号(继承自UNIX)
- 34~64:实时信号(Linux补充)
-
生命周期
-
信号的产生:
- 硬件:ctrl + c(SIGINT) ctrl + | () ctrl + z(SIGTSTP)
- 软件:
- kill signo pid
- int kill(pid_t pid,int sig) 给pid进程发送sig信号 (获取自己的pid:getpid() )
- int raise(int sig) 给调用进程发送sig信号
- void abort(void) 给调用进程发送SIGABRT信号
- unsigned alarm(unsigned int seconds)(定时器,sec秒之后通知进程)
seconds为零:取消上一个计时器 - core dumped:核心转储,文件命名方式:core.pid
- ulimit -a 查看 core dumped(核心转储)
- ulimit -c 1024//设置core文件的最大大小,单位是kb
- core.pid
- gdb ./main -> core-file core.pid -> bt
-
信号的注册:
- 在pcb的struct sigpending -> signal(位图)中标记收到了哪些信号,并且为这个信号组织一个sigqueue节点,添加到链表中
- 可靠信号: 34~64 :修改位图为1,并且为每个到来的信号都添加一个新的sigqueue节点
- 非可靠信号: 1~31 :判断位图是否为1,为1则什么也不做(事件丢失);否则添加节点修改位图
所以非可靠信号最多可以有1个节点,可靠信号可以有多个节点
-
信号注销
- 可靠信号和非可靠信号删除不同
- 可靠信号删除时去掉一个链表节点后需要判断是否还有相同的节点
- 如果有相同节点,位图置为1
- 如果没有相同节点,位图置0
- 非可靠信号直接删除节点,位图置0
-
信号处理
- 默认处理:操作系统中定义好的默认处理方式
- 忽略处理:什么也不做
- 自定义处理方式:用户自己定义的处理方式
- 修改信号处理方式: signal
- 默认:SIG_DFL
- 忽略:SIG_IGN
- sigaction(SIGINT,&act,&old) 用act替换SIGINT,将SIGINT保存在old中)
- 自定义信号处理方式的捕捉流程:
- 一个进程因为系统调用/中断/异常从用户态切换到内核态运行,完成功能后准备返回用户态的时候,查看是否有信号待处理,如果有,并且是默认或者忽略处理方式,则在内核态直接完成。如果有自定义处理方式,则返回用户态调用信号处理函数sigcb,完毕之后调用sigreturn返回内核态,当没有信号待处理,则调用sys_return返回用户态主控流程。
- 一个进程因为系统调用/中断/异常从用户态切换到内核态运行,完成功能后准备返回用户态的时候,查看是否有信号待处理,如果有,并且是默认或者忽略处理方式,则在内核态直接完成。如果有自定义处理方式,则返回用户态调用信号处理函数sigcb,完毕之后调用sigreturn返回内核态,当没有信号待处理,则调用sys_return返回用户态主控流程。
-
信号的阻塞
- 阻止信号被处理(递达)
- 在pcb中有一个信号阻塞集合,这个信号阻塞集合的作用就是用于标记哪些信号到来的时候暂时不被处理
SIG_BLOCK–block = block | set ->将set中的信号添加到阻塞集合
SIG_UNBLOCK–block = block & (~set)–>将set中的信号解除阻塞
SIG_SETMASK–block = set—>将阻塞集合设置位set中的信号
在所有信号中:SIGKILL -9 (强杀) SIGSTOP -19(停止) 无法被阻塞,无法被定义,无法被忽略 - 可靠信号和不可靠信号的区别
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
void sigcb(int signo)
{
printf("recv signo:%d\n",signo);
//通过打印查看收到信号
}
int main(int argc,char *argv[])
{
sigset_t set , oldset;
signal(SIGINT,sigcb); //修改信号处理方式为sigint信号
signal(40,sigcb); //修改信号处理方式为可靠信号40
sigemptyset(&set);
sigfillset(&set); //所有信号添加到set集合
sigprocmask(SIG_BLOCK,&set,&oldset);//set集合设置为阻塞
printf("press enter to continue\n");
getchar();
sigprocmask(SIG_UNBLOCK,&set,NULL);
sigprocmask(SIG_SETMASK,&oldset,NULL);
//通过将所有信号设置为阻塞,测试9号信号和19号信号不可被阻塞的特性
return 0;
}
这里使用4次40号信号
ctrl+c使用了7次只打印了1次,40号信号使用了4次打印了四次
这就是可靠信号和不可靠信号的区别