关于 Linux 信号详解

信号的基本概念

每个信号都有一个编号和一个宏定义名称 ,这些宏定义可以在 signal.h 中找到。

使用kill -l命令查看系统中定义的信号列表: 1-31是普通信号; 34-64是实时信号 

关于 Linux 信号详解

所有的信号都由操作系统来发!

对信号的三种处理方式

忽略此信号:大多数信号都可使用这种方式进行处理,但有两种信号却决不能被忽略。它们是:SIGKILL和SIGSTOP。这两种信号不能被忽略的,原因是:它们向超级用户提供一种使进程终止或停止的可靠方法。另外,如果忽略某些由硬件异常产生的信号(例如非法存储访问或除以0),则进程的行为是示定义的。

直接执行进程对于该信号的默认动作 :对大多数信号的系统默认动作是终止该进程。

捕捉信号:执行自定义动作(使用signal函数),为了做到这一点要通知内核在某种信号发生时,调用一个用户函数handler。在用户函数中,可执行用户希望对这种事件进行的处理。注意,不能捕捉SIGKILL和SIGSTOP信号。

1

2

3

 

#include <signal.h>

typedef void( *sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

 

signal函数的作用:给某一个进程的某一个特定信号(标号为signum)注册一个相应的处理函数,即对该信号的默认处理动作进行修改,修改为handler函数所指向的方式。

第一个参数是信号的标号

第二个参数,sighandler_t是一个typedef来的,原型是void (*)(int)函数指针,int的参数会被设置成signum

举个代码例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

 

#include<stdio.h>

#include<signal.h>

void handler(int sig)

{

    printf("get a sig,num is %d\n",sig);

}

 

int main()

{

     signal(2,handler);

     while(1)

     {

         sleep(1);

         printf("hello\n");

      }

      return 0;

}

 

  修改了2号信号(Ctrl-c)的默认处理动作为handler函数的内容,则当该程序在前台运行时,键入Ctrl-c后不会执行它的默认处理动作(终止该进程)

关于 Linux 信号详解

信号的处理过程:

关于 Linux 信号详解

进程收到一个信号后不会被立即处理,而是在恰当 时机进行处理!什么是适当的时候呢?比如说中断返回的时候,或者内核态返回用户态的时候(这个情况出现的比较多)。

信号不一定会被立即处理,操作系统不会为了处理一个信号而把当前正在运行的进程挂起(切换进程),挂起(进程切换)的话消耗太大了,如果不是紧急信号,是不会立即处理的。操作系统多选择在内核态切换回用户态的时候处理信号,这样就利用两者的切换来处理了(不用单独进行进程切换以免浪费时间)。

总归是不能避免的,因为很有可能在睡眠的进程就接收到信号,操作系统肯定不愿意切换当前正在运行的进程,于是就得把信号储存在进程唯一的PCB(task_struct)当中。

产生信号的条件

1.用户在终端按下某些键时,终端驱动程序会发送信号给前台程序。

     例如:Ctrl-c产生SIGINT信号,Ctrl-\产生SIGQUIT信号,Ctrl-z产生SIGTSTP信号

2.硬件异常产生信号。

     这类信号由硬件检测到并通知内核,然后内核向当前进程发送适当的信号。

     例如:当前进程执行除以0的指令,CPU的运算单元会产生异常,内核将这个进程解释为SIGFPE信号发送给当前进程。

               当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。

3.一个进程调用kill(2)函数可以发送信号给另一个进程。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/15064.html