欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

信号的概念和信号的产生

程序员文章站 2022-07-12 10:35:22
...

信号的概念:
这里提到信号,也有必要说一下信号量,信号量是进程间通信的一种方式,与现在要讲的信号并无关系。这里要区分开来。当操作系统接受到信号以后,会在合适的时候执行相应的动作。在我们的日常生活中,红绿灯是一种信号。而我们由于从小便被人告知,红灯停绿灯行……这种规则,因此,我们首先记住了红绿灯这个东西,随后,因为我们已经知道了红绿灯所对应的规则,当我们在遇到红绿灯时就会做出相应的动作。这里,操作系统也是一样,他先记录下信号,遇到信号以后就会在合适的时候去执行相应的动作(后面说明是什么时候)。
先来看一看Linux操作系统中的信号:

kill -l 命令即可查看系统定义的信号列表
信号的概念和信号的产生
其中1~31号信号叫做普通信号,34~64号信号叫做实时信号。
这里的每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到。
信号的产生:

1.通过终端按键产生信号
当我们在终端下按下某些键时会触发某些信号。比如Ctrl+c:触发SIGINT信号,Ctrl+\:触发SIGQUIT信号,Ctrl+z:触发SIGSTP信号
2.调用系统函数向进程发信号
这也就是我们终端上输入命令,比如kill命令
kill命令是调用kill函数实现的,kill函数可以给一个指定的进程发送指定的信号,还有raise函数可以给当前进程发送指定的信号(也就是自己给自己发送信号)。abort函数使当前进程接收到信号而异常终止。
例如我们运行一个简单的死循环的程序,将其放到后台运行,然后给该进程发送一个11号信号(SIGSEVG):
信号的概念和信号的产生
我们可以看到该进程已经发生段错误终止了,在这之前我们遇到的段错误都是访问了非法内存而引起的,现在这个程序并没有访问非法内存,在运行时(死循环)也没有发生段错误,而是我们通过kill命令给他发送了一个11号信号而产生的段错误。

再比如说abort函数,我们编写一个函数实现一下:

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int i = 0;
    for(;i < 100;i++)
    {
        printf("%d\n",i);
        if(i == 5)
            abort();
    }
    return 0;
}

由下图我们可以发现,abort函数被调用了,进程接收到信号就异常终止了
信号的概念和信号的产生

#include<signal.h>
int kill(pid_t pid,int signo);
int raise(int signo);
这两个函数都是成功返回0,错误返回-1.


#include<stdlib.h>
void abort(void);
就像exit函数一样,abort函数总是会成功的,所以没有返回值

3.有软件条件产生信号
SIGPIPE是一种由软件条件产生的信号,比如说当子进程在写的时候,父进程关闭了读端,此时子进程就会异常终止,父进程就会收到子进程的退出信号,这个退出信号就是13号信号,即SIGPIPE信号。下面来说一下alarm函数和SIGALRM信号。

#include<unistd.h>
unsigned int alarm(unsigned int seconds);
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号,该信号的默认处理动作是终止当前进程。

该函数的返回值为0或者是以前设定的闹钟时间还余下的秒数。打个比方,某人定上闹钟要睡觉30分钟,但是在闹钟还有10分钟(还剩20分钟)才响的时候,这个人被吵醒了,这时候他还想再继续睡一会儿,于是又定了一个闹钟30分钟。那么前一个闹钟余下的时间就是20分钟。如果seconds为0表示取消以前设定的闹钟,函数的返回值仍然是以前设定的闹钟时间还剩下的秒数。

#include<stdio.h>
#include<unistd.h>
int main()
{
    int i = 0;
    //设定以个5s的闹钟
    //5s之后给当前进程发送一个SIGALRM信号
    alarm(5);
    for(;i < 100;i++)
    {
        printf("%d\n",i);
        sleep(1);
    }
    return 0;
}

可以看出5s之后,操作系统向该进程发送了一个SIGALRM信号终止了该进程。
信号的概念和信号的产生

相关标签: 操作系统 信号