生活中有许许多多的信号,能够反映给人类,人类能够产生相应的行为。当我们使用键盘给计算机一个信号,计算机也会相应的产生一系列的行为。在linux系统中,使用kill -l命令能够查看系统中所有的信号如下:


‘信号’基本概念总结_signal

      其中:系统中总共有62中信号,前31种信号称为普通信号,后31中称为实时信号。当然在这里主要讨论的是前31种。


★信号产生

(1)信号产生的方式主要有以下4种:

         ①键盘:当一个进程正在运行时,可以从键盘上输入ctrl+c使得进程终止,其实是键盘上输入的信息被系统捕捉,系统向前台进程发送2号信号(即就是SIGINT),进而将程序进行终止。

         注:信号反映于前台,后台没有作用,不能使得程序终止。向后台反映使用&,如:./test &

 

例:

‘信号’基本概念总结_信号递达_02

运行结果:

‘信号’基本概念总结_信号递达_03


           ②命令:可以使用kill  [信号]  PID  这个命令。如:kill -2 10236


           ③函数:可以使用raise( )函数和abort( )函数。

                    int kill(pid_t pid, int signo);

                       int raise(int signo);

                       void abort(void);


          ④软件条件:利用alarm函数,设置闹钟,等到一定时间后,向当前进程发送SIGALRM信号。


例:

‘信号’基本概念总结_信号递达_04

运行结果:

‘信号’基本概念总结_阻塞信号_05



★信号处理

(1)进程的处理方式有3种:

           ①忽略此信号

           ②执行默认的处理方式

           ③提供自定义的信号处理函数,将其称为捕捉


     注:①绝大部分进程接收到信号不会立即进行处理的,会先将其保存在自己的PCB中,等到合适的时候进行处理。

            ②信号的默认处理方式是终止进程。


(2)相关概念:

           信号未决:将信号产生到信号执行之前这段时间称为信号未决。

           阻塞:进程可以阻塞某个信号,被阻塞后的信号只有解除阻塞,才能够进行执行。

           信号递达:将信号的处理动作称为递达。


     注:信号的产生和阻塞是没有关系的,所以即使没有产生信号,系统也可以将此种信号进行阻塞。


‘信号’基本概念总结_阻塞信号_06

      在linux系统中,只记录产生了哪种信号,并不会将信号的次数进行记录,所以只需要将31种信号用4个字节(32)位来进行表示,这些信息都会保存在进程的PCB中,存在block、pending、handler。block表示每个信号是否被阻塞,0表示没有阻塞,1表示被阻塞。pending表示进程中是否存在某种信号,0表示不存在,1表示存在,。handler表示存储方式,SIG_DFL表示执行默认的处理方式,SIG_IGN表示忽略此信号。

      未决和阻塞都可以使用相同的数据类型sigset_t来存储,可以表示有效、无效两种状态,分别称为‘信号屏蔽字’和‘pending信号集’。

      注:信号集中不能使用位运算来进行操作。


★信号集操作函数

       头文件:#include <signal.h>

        函数:int sigemptyset(sigset_t* set);               //将信号集中所有的数据置为无效

                     int sigfillset(sigset_t* set);                      //将信号集中所有的数据置为有效

                     int sigaddset(sigset_t* set, int signo);    //在信号集中增加哪个信号

                     int sigdelset(sigset_t* set, int signo);     //删除信号集中的某个信号

                     int sigismember(const sigset_t* set, int signo);    //判断某个信号是否在信号集中

        int sigprocmask(int how, const sigset_t* set, sigset_t* oset);   //获取或更改进程的信号屏蔽字

        int sigpending(sigset_t* set);         //获取当前进程的未决信号集


例:

‘信号’基本概念总结_阻塞信号_07

运行结果:

‘信号’基本概念总结_信号递达_08


★捕捉信号

     在上面提到信号产生后,进程不是立即对其处理,而是先将其保存在自己的PCB中,等到合适的时候来处理。其实,合适的时候就是:在由于某些异常原因,进程从用户态切换到内核态,返回之前需要对信号进行检查、处理(即就是内核态到用户态切换时)。


     int sigaction(int signo, const struct sigaction* act, struct sigaction* oact);   //读取和修改指定信号的处理动作。

     int pause(void);     //将进程挂起,直到有信号递达


例:使用上面两个函数完成sleep函数


‘信号’基本概念总结_signal_09

运行结果:

‘信号’基本概念总结_signal_10


      注:这里不考虑多线程的切换问题。