linux的信号

来源:互联网 发布:梦里花落知多少微微 编辑:程序博客网 时间:2024/06/04 18:12

Linxu系统支持30种不同种信号,每种信号都是对应系统的某种事件,底层硬件的异常是由内核异常处理程序处理的,正常情况下,对于用户进程是不可见的。

信号提供了一种机制,通知用户进程发生了这些异常。例如:当进程在前台运行的时候,按下ctr+c内核向当前进程发送SIGINT的信号给前台进程,默认操作是终止运行。

概念:

1.发送信号:内核通过更新目的进程的上下文的某个状态,发送信号给目的进程,原因有两个

1.内核检测到了系统事件,比如除数为0.子进程终止

2.一个进程调用了kill函数,显示的要求内核发送信号给目的进程

2.接收信号:目的进程被内核强迫以某种方式对信号的发送做出反应的时候,就接收了信号。进程可以选择忽视,也可以通过信号处理程序捕获信号---signal函数

3.待处理信号:发出还未接收的信号。

注意:任何时刻一种类型的信号至多有一个待处理信号。如果一个进程有一个类型为k的待处理信号,接下来发送的任何为k的信号不会排队等待,会被丢弃。

   一个进程可以选择性的阻塞某种信号,当一个信号被阻塞时,但是产生的待处理信号不会被接收,直道进程取消对这种信号的阻塞。

如何发送信号呢,linux系统提供了大量的机制,但是都是基于进程组这个概念的,默认的子进程和它的父进程属于同一个进程组。

每个进程都只属于一个进程组,进程组是一个正整数进程组ID来标识的。可以通过getpgrp和setpgid获取或者改变进程组

发送信号方法:

       1. /bin/kill程序可以向另外的进程发送任意的信号,比如 /bin/kill -9 -15211发送信号SIGKILL给进程15213,如果PID为负数,会认为是进程组号,给进程组所有进程发送信号。

2.键盘发送,比如常见的ctrl-c,内核发送SIGINT信号给前台进程组的所有的进程,linux外壳使用job的抽象概念表示一个对一个命令行求值创建的进程,任何时刻至多有一

个前台作业和0或者多个后台作业。外壳为每个作业创建了一个独立的进程组。典型的进程组ID是取自作业中父进程ID的一个,组长进程。

       3.kill函数发送信号,这里的kill和第一个提到的不一样。这里的是一个底层函数,另一个是shell的内置命令。Kill(pid,sig);

       4.用alarm函数发送信号。

案例:通过alarm产生产生的1s中断,计时5秒。

void handler(int sig){    static int count=0;//定义静态局部变量    printf("%d\n",count);    if(++count<5)    {        alarm(1);    }    else    {        printf("end");        exit(0);    }}int main(){    signal(SIGALRM,handler);    alarm(1);//使得内核在1s内发送信号SIGALRM给进程    while(1)    {        ;    }    exit(0);}

接收信号:

内核从一个异常的处理程序返回,准备将控制传递给进程p的时候,它会检查p未被阻塞的待处理的信号的集合,如果为空,内核将控制传递到p的逻辑控制流的下一条指令。

如果非空,内核选择集合的某个信号k通常k是最小值,并强制p接收信号k,收到这个信号会触发进程的某个行为,完成后,控制就传递回p的逻辑控制流中的下一个指令。

(就是说,中断函数处理完成后,内核会看看是否还有没有没有被阻塞但是还有处理的中断时间,比如在处理中断函数的时候又来信号了,来了不止一个,那么就从里面选择编

编号最小的处理,当然这样可能性不大,通常就是处理完后返回main函数继续运行)

在程序编写的时候首先要用signal函数在主程序里面安装信号处理,signal(signum,handler),第一个参数信号的编号,第二个是处理函数的函数指针。



0 0