信号的概念:
系统预先定义好的某些特定事件:可以被发生,也可以被接受。发生和接受的主体都是进程。
信号的响应方式有以下几种:
默认0
忽略1
自定义
忽略1
自定义
SIG_DFL
SIG_IGN
0
1
可以同过signal函数修改信号的响应方式
typedef void
(*fun_handle)(int );
(*fun_handle)(int );
fun_handle signal(int
sig_num,fun_handle fun);
sig_num,fun_handle fun);
fun参数简单来理解就是自己定义的相应方式的函数。
signal一般在进程刚开始的时候 即main()里 第一行调用
接下来将用处理僵死进程来说明signal函数的作用
制造僵死进程的代码如下
#include<stdio.h>
#iclude<signal.h>
int main(void)
{
int res=fork();
if(res==0)
{
sleep(2);
printf("kid start");
sleep(2);
printf("kid over")
}
else
{
printf("father start");
while(1);
}
return 0;
}
上面代码的运行结果应该是先是father start 打印在屏幕上,过了2秒 kid start 打在了屏幕上。又过了2秒
kid
over打印在了屏幕上,至此,子进程已经运行结束了,父进程仍在while(1)中,子进程就变成了僵死进程。
kid
over打印在了屏幕上,至此,子进程已经运行结束了,父进程仍在while(1)中,子进程就变成了僵死进程。
如何让处理僵死的子进程呢。
子进程结束的时候都会向父进程发送一个信号。(这是系统默认会做的)
父进程会在运行即将结束的时候处理这个信号。杀掉子进程,让它占用的pcb释放。(这也是默认的)
但僵死进程出现的原因就是因为往往父进程要运行的时间往往很长,不能及时处理这个信号,导致子进程必须随着父进程的慢节奏才能被收尸。这是我们不希望看到的。
因此我们要修改父进程中,处理子进程信号的函数。让它达到一种效果。那就是父子进程可以同时开始运行,如果子进程一结束发回信号,父进程就能立刻调用处理函数来杀掉子进程
(杀子进程的时间微乎其微可以忽略),然后再继续运行父进程。让父进程也不会阻塞 (其实是有的,但时间很短可以忽略)。
(杀子进程的时间微乎其微可以忽略),然后再继续运行父进程。让父进程也不会阻塞 (其实是有的,但时间很短可以忽略)。
由于子进程发回的是SIGCHLD信号,因此我们就要用signal函数对SIGCHILD信号进行处理。
signal(SIGCHLD,0)为默认当然不是我们想要的,默认的话就会出现僵尸进程。
signal(SIGCHLD,1)为忽略
当然也不是我们想要的,这样的话就算父进程结束,子进程也没人给收尸了,因为就算父进程结束,接受了SIGCHLD信号也视而不见。既然看不见SIGCHLD信号那就不会做出给子进程收尸的反映了。我们知道很基本的原理就是
给信号---做反应。
当然也不是我们想要的,这样的话就算父进程结束,子进程也没人给收尸了,因为就算父进程结束,接受了SIGCHLD信号也视而不见。既然看不见SIGCHLD信号那就不会做出给子进程收尸的反映了。我们知道很基本的原理就是
给信号---做反应。
所以我们要自定义一种处理的方式。
signal(SIGCHLD,fx);
fx就是一个函数 。执行fx里面的内容就是对SIGCHLD做的反映。
因此我们就写一个处理子进程的函数
void fx(int a)
{
wait(NULL);
printf("son is killed by
fx()!");
fx()!");
}
一旦子进程结束发回了SIGCHLD信号,父进程立刻对SIGCHLD信号做出反应。原本的反应应该是等父进程运行快结束再wait子进程。但我们用了signal修改了反应的内容,那就是立刻调用fx函数。fx会立刻wait子进程。然后潇洒的打印一句
son is killed by fx()!;
这样的话,子进程就立刻被释放了,我们也达到了即使处理僵死进程的目的。
son is killed by fx()!;
这样的话,子进程就立刻被释放了,我们也达到了即使处理僵死进程的目的。