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