Linux之信号
信号:信号和信号量不是同一个东西,信号是通知进程发生了某个事件,用来打断进程当前正在进行的操作,去处理这个事件,是一个软件终中断,功能是事件通知。
== 信号的分类==
信号分为可靠信号和非可靠信号,利用kill -l命令查看信号
非可靠信号:1---31号(可能会发生信号丢失)
可靠信号:34---64号(不会丢失)
信号的生命周期
产生—>在进程中注册---->在进程中注销—>处理; 阻塞
信号的产生:
硬件产生:ctrl+c中断 ctrl+z停止 ctrl+\退出
软件产生:kill命令 kill -signum pid 示例:kill 9 pid;
int kill((pid_t pid,int signum);给指定的进程发送指定的信号
int raise(int signum);给进程自身发送指定的信号
void abort() 给进程自身发送SIGARBT信号(异常信号)
int alarm(int sec)定时器---sec秒之后给进程自身发送SIGALRM信号
(注意!!!alarm信号是一个定时器,他会取消之前的计时器,如果写在循环里面,
会导致没有产生定时功能)
在进程中注册:
在进程pcb中有个表 位图—>未决(未被处理的)信号的集合,进程运行中通过这张表的数据能够获知自己收到了哪个信号。
信号在进程中注册,说白了就是修改位图中的标志位,将对应的信号位置置为1,位图只能看出信号收没收到,不能看出收到了多少次
在pcb中还有一个sigqueue双向链表,链表中有多少个相同的信号
信息节点,就表示信号注册了多少次
非可靠信号的注册:如果信号已经被注册(没有被执行),那么不作任何操作,否则进行注册。
可靠信号的注册:不管信号注册没有,都要进行一次注册(添加一个信号节点)
== 可靠信号,相同的信号在链表中可能有多个节点,但是非可靠信号最多只能有一个==
信号的注销:消除信号在pcb中的痕迹,删除一个信号的sigqueue节点,没有相同的节点了则位图置为0.
信号的处理:
处理一个时间,就是执行一个功能,信号的处理,就是调用处理信号的函数,执行这个函数,信号处理的时间,由进程自己察觉到自己受到某个信号才进行处理。
信号的处理方式有多种的,并且是可修改的。
默认处理方式:(系统中既定义的 SIG_DFL)
忽略处理方式:针对这个事件,处理方式就是什么都不做(SIG_IGN忽略处理方式 ),9号信号和19号信号不可被忽略
自定义处理函数:程序员自定义一个信号处理函数—作为指定的信号处理函数
回调函数 typedef void(*sighander_t)(int)
sighander_t signal(int signum–信号值 , sighander_t hander–函数指针);----->signum:指定要修改哪个信号处理方式的信号值 hander—>指定signum新的信号的信号处理函数
返回值:返回signum信号原有的信号处理函数的地址
用户态与内核态
用户态:程序运行的是我们自己写的或者是库函数,在用户态运行
内核态:运行内核中的某个代码来执行内核上的功能
如何从用户态------>>内核态:
1.系统调用
2.中断
3.异常
== 信号的处理:是在内核态返回用户态之前完成的,默认和忽略处理方式是在内核态完成的,自定义处理方式是在用户态完成的,完毕后,依然会返回内核态,直到没有待处理信号,才会返回主控流程==
信号的阻塞:说白了就是信号到来的时候不去处理,直达解除了阻塞之后才去处理,在pcb中有一个阻塞信号的集合(位图),一个信号阻塞就表示将这个信号添加到阻塞信号的位图中去,起始就是做个标记,一个信号解除阻塞就是将这个信号从阻塞的集合中拿出来,说白了就是解除标记。
int sigprocmask(int how,const sigset_t *set,sigset_t *oldset);
how:表示要对阻塞集合进行的操作
SIG_BLOCK/SIG_UNBLOCK/SIG_SETMASK
set:
SIG_BLOCK将set集合中的信号添加到阻塞队列中去,将原来的阻塞信号集合中的信号放到old中去
SIG_UNBLOCK:将set集合中的信号从阻塞队列中移除,说白了就是解除set中的信号阻塞
SIG_SETMASK:直接将阻塞集合的值修改为set
oldset:用于保存修改前原有阻塞信号的集合(便于还原),可以置NULL
sigset_t:是一个信号位图的结构体
返回值:成功返回0,失败返回-1;
int sigemptyset(sigset_t *set);清空set集合
int sigfillset(sigset_t *set); 将所有的信号添加到set集合当中去
int sigaddset(sigset_t *set,int signum);将指定的signum信号添加到set集合中去
int sigdelset(sigset_t *set,int signum);将指定的signum信号从set集合中移除
int sigismember(const sigset_t*set,int signum);判断signum信号是否在set集合中