首页 > 代码库 > Linux信号处理2

Linux信号处理2

引言

先看以下两个信号量:

13)SIGPIPE     当管道读端关闭,再往管道写东西,会发出SIGPIPE信号
17)SIGCHLD   子进程退出会向父进程发出SIGCHLD信号,系统默认处理是忽略掉该信号

代码

/*************************************************************************    > File Name: my_fork.c    > Author: KrisChou    > Mail:zhoujx0219@163.com     > Created Time: Mon 25 Aug 2014 10:42:26 AM CST ************************************************************************/#include<stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <sys/wait.h>#include <signal.h>void handler(int num){    pid_t pid ;    printf("sig_num: %d \n", num);    pid = wait(NULL);    printf("wait : %u \n", pid);}int main(int argc, char* argv[]){    int fds[2];// fds[0] r  fds[1] w    pipe(fds);    char buf[1024];    signal(SIGPIPE, handler);    signal(SIGCHLD, handler);    if(fork() == 0)    {        close(fds[1]);        while(memset(buf, 0, 1024), read(fds[0], buf, 1024))        {            write(1, buf, strlen(buf));        }        printf("child over ! \n");        exit(0);    }    if(fork() == 0)    {        exit(0);    }    if(fork() == 0)    {        exit(0);    }    close(fds[0]) ;    while(memset(buf, 0, 1024), read(0, buf, 1024))    {        write(fds[1], buf, strlen(buf));    }    //while(1) ;    return 0 ;}

运行结果如下:

[purple@localhost review]$ ./a.outsig_num: 17wait : 15693sig_num: 17wait : 15692hellohelloworld!world!child over !

程序运行时,先是两个子进程先后退出,向父进程发送SIGCHLD 信号,接着执行handler函数,回收两个子进程资源。接着程序执行到父进程的while循环,由于read是阻塞函数,在我们没有按下enter或者ctrl+d之前,时间片会在第一个子进程和父进程之间来回切换。如果输入字符按enter,那么也就是父进程将其写入管道,子进程将其从管道中取出,并显示在屏幕上。

如果按ctrl+d,则父进程退出while循环,并且退出程序。此时第一个子进程成为孤儿进程,被init收养,子进程退出时,会向init发送SIGCHLD 信号,由init回收资源。(注意,init很猛的,它本身就已经将SIGCHLD 注册了,其信号处理函数实现了回收资源)

干货

我们之所以将回收子进程资源的wait函数写在信号处理函数中,是因为wait是阻塞函数。如果父进程阻塞了就不能处理自己的工作了。

之前我们已经提过,当子进程终止时,会给父进程发送SIGCHLD信号,虽然该信号的默认处理动作是忽略,但是父进程可以自定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程,当子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程资源即可。

通常情况下服务器是永远不会退出的,因此我们可以在之前的程序中 return 0 前加个while(1),以此来模拟服务器。

注意

如果父进程先于子进程退出,则子进程成为孤儿进程,此时将自动被PID为1的进程(即init)接管。孤儿进程退出后,它的清理工作有祖先进程init自动处理。但在init进程清理子进程之前,它一直消耗系统的资源,所以要尽量避免。

如果子进程先退出,系统不会自动清理掉子进程的环境,而必须由父进程调用wait或waitpid函数来完成清理工作,如果父进程不做清理工作,则已经退出的子进程将成为僵尸进程(defunct),在系统中如果存在的僵尸(zombie)进程过多,将会影响系统的性能,所以必须对僵尸进程进行处理。

Linux信号处理2