(Linux)进程信号

进程信号

信号:信号是一个软件中断;
作用:操作系统通过信号告诉进程发生了某个事件,打断进程当前操作,去处理这个事情
操作系统中的信号:通过 kill -l 命令可以查看系统中的信号种类(62种)

1~31好信号:从Uinux借而来,每个信号都有具体对应的系统事件;(非可靠信号,有可能丢失信号);
34~64号信号:后期补充的,因为没有具体对应的事件,因此命名比较草率;(可靠信号,不会丢失信号);

信号的生命周期:1、产生;2、在进程中注册;3、在进程中注销;4、信号处理;

信号产生

硬件:ctrl+c / ctrl+z /ctrl + |
软件:kill -signum pid命令 kill默认发送15号进程 /kill(int pid, int signum) / raise(int signum) / abort( ) /alarm(int seconds)
kill杀死一个进程的原理:向进程发送一个信号,信号有对应的事件,进程放下手头工作去处理这个事件,然而事件的处理结果就是让进程退出。fg的功能是将一个暂停的后台程序调到前台运行

  • kill(进程id,信号值)
  • kill(getpid(),SIGHUP); // 给指定进程发送指定的信号
  • raise(SIGTERM); //给进程自己发送指定的信号
  • abort( ); //给自己发送SIGABRT信号通常用于异常通知
  • alarm(3); //3秒之后给进程自己发送SIGALRM信号(相当于定时器)

信号在进程中注册

如何让进程知道自己收集了某个信号;pcb -> struct sigpending -> struct sigset_t
sigset_t这个结构体中只有一个数据成员;这个数组用于实现一个位图 - - - 称之为未解决信号集合(收到了但是没有被处理的信号集合);
给一个进程发送一个信号,就会将这个位图中对应位置为1,表示进程当前收到了这个信号;
信号的注册其实不仅会修改位图,还会为信号组织一个sigqueue节点添加到pcb的sigqueue链表中;

  • 1~31号非可靠信号注册:若信号注册的时候位图为0,则互创建一个sigqueue节点并修改位图为1,但是若位图为1,则什么也不做;
  • 34~64号可靠信号的注册:不管位图当前是否为0,都会创建一个节点,添加到链表中,并修改位图;

信号在进程的注销

为了保证一个信号只会被处理一次,因此先注销再处理;在pcb中删除当前信号信息;将pending位图置为0;删除信号节点;
非可靠信号注销:因为非可靠信号只会有一个节点,因此删除节点后,位图直接置为0;
可靠信号注销:因为可靠信号有可能注册多次,有多个节点,因此删除节点后,需要判断是否还有相同节点,若没有才会将位图置为0;

为什么要注销?(先注销后处理)
答:因为有这个信号需要处理,并且取出了这个信号的信息,因此注销之后就立即去处理;这样保证一个信号只会被处理一次。

信号的处理

信号表示一个事件的到来,处理事件就是完成功能,(在C语言中完成一个功能的最小模块为- - -函数)。
其实每一个信号都对应有自己的事件处理函数,信号到来,去处理这个事件就是去执行这个处理函数;执行完毕事件就处理完了。

信号的处理方式:

  1. 默认处理方式:操作系统中原定义好的每个信号的处理方式;
  2. 忽略处理方式:处理方式就是忽略,什么也不做;
  3. 自定义处理方式:自己定义一个事件函数,使用这个函数替换内核中默认的处理函数;信号到来就会调用我们定义的函数了。
    (Linux)进程信号
    typedef void(*sighandler_t)(int); - - - - 定义了一个名称为sighandler_t的函数指针类型。
    sighandler_t signal(int signum,sighandler_t handler);
    handler :SIG_DFL- - - 默认处理方式 / SIG_IGN - - - 忽略处理方式 / 用户自己定义的一个没有返回值,有个int型参数的函数地址。
    (Linux)进程信号