信号的基本概念
每个信号都有一个编号和一个宏定义名称 ,这些宏定义可以在 signal.h 中找到。
对信号的三种处理方式
- 忽略此信号:大多数信号都可使用这种方式进行处理,但有两种信号却决不能被忽略。它们是: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后不会执行它的默认处理动作(终止该进程)
信号的处理过程:
进程收到一个信号后不会被立即处理,而是在恰当 时机进行处理!什么是适当的时候呢?比如说中断返回的时候,或者内核态返回用户态的时候(这个情况出现的比较多)。
信号不一定会被立即处理,操作系统不会为了处理一个信号而把当前正在运行的进程挂起(切换进程),挂起(进程切换)的话消耗太大了,如果不是紧急信号,是不会立即处理的。操作系统多选择在内核态切换回用户态的时候处理信号,这样就利用两者的切换来处理了(不用单独进行进程切换以免浪费时间)。
总归是不能避免的,因为很有可能在睡眠的进程就接收到信号,操作系统肯定不愿意切换当前正在运行的进程,于是就得把信号储存在进程唯一的PCB(task_struct)当中。
产生信号的条件
信号的产生
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/*************************************************************************
> File Name:
test
.c
> Author:Lynn-Zhang
> Mail: [email protected]
> Created Time: Fri 15 Jul 2016 03:03:57 PM CST
************************************************************************/
#include<stdio.h>
int main()
{
printf
(
"get pid :%d circle ...\n"
,getpid());
while
(1);
return
0;
}
|
kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定信号。
raise函数可 以给当前进程发送指定的信号 (自己给自己发信号 )
1
2
3
|
#include<signal.h>
int
kill(pid_t pid,
int
signo);
int
raise
(
int
signo);
|
1
2
|
#include<stdlib.h>
void
abort
(
void
);
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/*************************************************************************
> File Name: alarm.c
> Author:Lynn-Zhang
> Mail: [email protected]
> Created Time: Fri 15 Jul 2016 08:52:02 PM CST
************************************************************************/
#include<stdio.h>
int
main()
{
int
count=0;
alarm(1);
while
(1)
{
printf
(
"%d\n"
,count);
count++;
}
return
0;
}
|
通过实现以上代码,调用alarm函数可以设定一个闹钟,告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动作是终止当前进程。
该程序会在1秒钟之内不停地数数,并打印计数器,1秒钟到了就被SIGALRM信号终止。由于电脑配置等的不同,每台电脑一秒钟之内计数值是不同的一般是不同的。
1
2
|
#include <unistd.h>
unsigned
int
alarm(unsigned
int
seconds);
|
alarm函数的返回值是0或上次设置闹钟剩余的时间。