信号
信号的基本认知:软件的中断,通知时间的发生
生命周期
信号的种类(kill -l)
Linux:62种:1-31对应不同的事件 非可靠信号/非实时(事件可能会丢失/是否立即会处理)
34-64用户添加的信号 可靠信号/实时信号
信号的生命周期:产生–>注册–>注销–>处理 阻塞
信号的产生:
1.硬件产生:Ctrl+c Ctrl+l Ctrl+z
2.软件产生:kill kill() raize()abort()alarm()
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
给指定进程发送指定信号
sig 信号种类
int raise(int sig);
给自己发送信号
#include <stdlib.h>
void abort(void);
给调用进程发送SIGABRT信号
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
给调用进程指定时间后发送SIGALRM信号
返回上一个定时器剩余的时间或0
参数为0表示取消定时器返回上一个定时器的剩余时间
core dumped :黑匣子,默认关闭,站磁盘资源
进程异常运行时,保存信息到core.pid文件中方便调试
ulimit -a 查看是否开启0
ulimit -c 1024 设置大小,开启核心转储文件
gdb./loop --> c ore-file core.pid -->bt
信号的注册:信号在进程的注册 sigset_t
信号注册
在pcb中做标记:修改未决信号集合(位图)对应的信号位
task_struct->struct sigpending pending->sigset_t signal
非可靠信号的注册:判断是否有相同的未决信号,若有,则什么也不做;否则修改位图添加结点
可靠信号的注册:是否有相同未决信号的注册,若没有修改位图添加节点;否则直接添加结点
信号的注销:删除信号的sigqueue结点,修改pending位图
非可靠信号注销:删除节点,修改位图(非可靠信号只会注册一次)
可靠信号注册:删除节点,检测是否还有相同信号,若有则位图依然置1否则修改为0
信号的处理:
默认处理方式:
忽略处理方式:
自定义处理方式:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signum信号编号
handler 函数指针使用函数指针替换signum的处理方式
SIG_DEL
SIG_IDN
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
自定信号处理方式的处理流程:用户态切换回内核态,完毕后准备从内核态切换回用户态的时候去处理信号
若信号为默认或者忽略处理,则在内核中直接完成,但是信号如果是自定义的处理方式,则需要返回用户态执行信号回调函数,执行完毕后回到内核态没有信号则回到信号主流程
信号阻塞:阻止信号被递达(站不处理信号)
在进程pcb中标记 那些信号来了不处理
在进程pcb中有个信号阻塞集,阻塞信号就是在这个集合做标记
有两个信号无法被阻塞,忽略,自定义SIGKILL,SIGSTOP19
接口
静态条件:
时序的竞争执行:函数的可重入与不可重入(是否进行了)对全局数据的非原子性操作
关键字:volatile:保持内存可见性—防止编译器过度优化-每次对变量访问都从内存重新获取
SIGCHLD:子进程退出,操作系统通知父进程,自定义一个SIGCGLD信号处理方式sigcb,当子进程退出操作系统发送信号给父进程直接触发信号回调sigbc用户主要在sigbc中调用wait/wait_pid就可以处理子进程退出
sigchld是一个非可靠信号,假如有多个子进程同时退出则有可能造成事件丢失导致sigbc只被调用一次,只处理了一个子进程因此需要在sigcb中需要用户循环非阻塞处理子进程退出,直到没有子进程退出
while(waitpid(-11,NULL,WONOHANG)> 0)//因为>0表示有子进程退出必须用非阻塞,否则没有子进程·退出的时候waitpid将阻塞导致进程无法回到主控流程