一,信号的产生
信号的产生有三种方式:
硬件产生:CTRL + C,CPU,MMU报错等,发出的信号
软件产生:进程读写文件时发生错误,如另一个进程关掉了文件描述符,alarm信号等
kill命令:系统调用,软件调用。
注意:1.CTRL+C 只能给前台进程发送信号,而不能给后台进程发送信号。后台运行命令 例如: ./ test &
2.进程中如果出现野指针,那么它通过页表和MMU映射的时候,会发生错误,在MMU中纪录下来,操作系统会知道进程非法操作,会对它发送信号,终止掉进程。这种方式也是硬件产生的。
3.操作系统只是一个执行者的身份,并不是它产生的信号,但是它具有修改信号的权限。
二,信号具体流程
信号产生的三种方式----> 操作系统---------> 进程----------->进程处理信号
1.进程处理信号前提是识别信号,操作系统给进程的位图表至为一,进程会进行检测。
2.信号的产生,进程并不一定会立即处理,而是在合适的时候处理
3.信号产生对进程而言是异步的,因为它并不会立即处理信号。
三,信号处理的方法
1,执行默认动作(比如终止进程)
2.忽略信号
3.执行自定义动作(这也称为捕捉信号)
4,如果无法立即处理信号应记录下来,具体为:记录到进程的pcb,PCB中包含记录信号的数据结构位图,位置表示编号,内容表示是否产生信号。
四,信号的种类
在Linux中,信号一共有62个,其中1-31是普通信号,它们只能接受一次信号,重复信号忽略,34-64是实时信号,重复信号在一个队列里。其中普通信号是宏定义的。
SINGINT(Ctrl +c) 默认动作---终止进程,SINQUIT默认动作(Ctrl -\)-----终止进程并且Core Dump,其他还有很多,这里讲解一下,Core Dump。
程序退出有三种情况:代码跑完,结果的对
代码跑完,结果错误
代码没跑完,有信号终止
1.在status状态中,是用位图来记录,我们是能够获取到信息的,其中,后8位就是,就是用来查看收到了几号信号,其中的第一位就是,core dump,当进程要异常终止时,可以选择把进程的用户空间内存数据全部保存在磁盘上,文件名叫core,这就叫做core dump----核心转储,用来事后查看错误信息的
2.一个进程允许产生多大的core文件取决于进程的Resource Limit(这个信息保存在PCB中),默认是你不允许产生core文件的,因为它包含了用户密码等敏感信息,不安全。
3.在Linux中,首先用 ulimit-c 1024 命令使他能够产生core文件,然后用Ctrl -\ 终止,我们就可以用gdb调试,查看错误信息了。
五,信号的捕捉
信号捕捉也就是自定义执行动作,在handler 这个指针数组里,加入我们自定义的函数地址。
捕捉函数有singnal (被捕捉的信号,handler(方法))
sigaction(信号标号,新的信号,旧的信号)
sigset_t:数据类型,叫做信号集,用来存储block(有没有被阻塞),pending(有没有递达)位图的。
其他函数:
sigempty(sigset_t *set) 初始化为0
sigfillset(sigset_t *set) 置位
sigaddset(sigset_t *set,int signo)添加信号
sigdelset(sigset_t *set,int signo) 删除信号
sigprocmask(int how,const sigset_t *set,sigset_t *oset) 读取或更改进程的信号屏蔽字(阻塞信号集)
信号处理的原理过程:
1.当在执行主控制流程指令时,用中断或异常,系统进入内核。
2内核处理完,先处理当前进程可以递达的信号。
3,如果是自定义的信号,必须从内核态,切换到用户态,处理完再回到内核态。
4,返回上次被中断的地方继续向下执行。
六,SINCHLD信号
我们知道当子进程退出的时候,父进程必须回收,不然会产生僵尸进程,但是这样父进程的任务就太重了。
其实子进程在退出的时候会给父进程发送SINCHLD信号,我们可以自定义SINCHLD信号,让它去回收子进程就好了。