僵死进程(《精通Unix下C语言编程与项目实践》之五)

文章试读
不拘一个遍程序系列:编程序不能一个脑袋钻到底,有时要学会变通,即所谓的曲线救国。一、二、三、四
职场规划:一些杂七杂八的职场感悟吧。不值钱的软件人才 精力充沛与事业成功 让系分来得更猛烈些吧
我的诗歌:都是我的打油诗,但是很值得一读。不要工作还衣食无忧之四难歌   香格里拉美人图
宝宝图片:超可爱的小宝宝 写博客
考试培训:主要是关于考研、软考和等级的相关题解。2009考研试题分析 2008年12月程序员试题分析
 
 
 
《精通Unix下C语言编程与项目实践》之五
僵死进程 
作者:朱云翔,胡平

9.3 僵死进程

僵死进程是已经终止,但没有从进程表中清除的进程。代码 9-12 展示了一个产生僵死进程的例子:
代码 9-12 僵死进程产生模型(节自 /code/chapter9/szomb1.c
#include <unistd.h>
#include <stdio.h>
void main()
{
    pid_t pid1;
    if ((pid1 = fork()) == 0)
    {
        printf("child[%d]\n", getpid());
        exit(0);
    }
    /* wait(); */           /* */
    printf("parent[%d]\n", getpid());
    sleep(60);
}
编译代码 9-12
# make szomb1
        cc -O -o szomb1 szomb1.c
后台运行程序 szobm1 ,并在子进程结束后,父进程没有结束前,运行命令查询进程情况:
# ./szomb1&
10570
# child[10571]
parent[10570]
# ps -ef|grep 10570
    root 10570 10449  0 19:25:50   ttyp0    00:00:00 ./szomb1
    root 10571 10570  0        -       -    00:00:00 <defunct>
其中“ <defunct> ”代表僵死进程(不同版本 Unix 描述略有不同)。因此可知,子进程并没有如期消失,而是转化为僵死进程继续占用系统进程表资源。 如果系统存在大量的僵死进程,就会过多占用进程表空间,影响新进程的产生。 对于僵死进程,不能奢望通过 kill 命令杀死之,因为它已经“死”了,不再接收任何系统信号。
当子进程终止时,它释放资源,并且发送 SIGCHLD 信号通知父进程。父进程接收 SIGCHLD 信号,调用 wait 返回子进程的状态,并且释放系统进程表资源。故如果子进程先于父进程终止,而父进程没有调用 wait 接收子进程信息,则子进程将转化为僵死进程,直到其父进程结束。
一旦知道了僵死进程的成因,我们就可以采用如下方法预防僵死进程:

1. wait

父进程主动调用(或者接收到 SIGC(H)LD 信号后调用) wait 接收子进程的死亡报告,释放子进程占用的系统进程表资源。如将代码 9-10 中屏蔽的代码行 wait(); ”打开,就可以有效的阻止僵死进程的产生。

2. 托管法

如果父进程先于子进程而死亡,则它的所有子进程转由进程 init 领养,即它所有子进程的父进程 ID 号变为 1 (进程 init 的标识为 1 )。当子进程结束时 init 为其释放进程表资源。

3. 忽略SIGC(H)LD信号

当父进程忽略 SIGC(H)LD 信号后,即使不执行 wait ,子进程结束时也不会产生僵死进程(有关信号的相关知识将在下一章讲述)。

3. 捕获SIGC(H)LD信号

当父进程捕获 SIGC(H)LD 信号,并在捕获函数代码中等待( wait )子进程。
【实践经验】实现托管法的技巧是调用 fork 两次,让子进程退出,子子进程的父进程更改为进程 init ,这样父进程就不必理会子子进程的处理了。代码 9-13 设计了一个两次 fork 避免僵死进程的例子。
代码 9-13 托管法预防僵死进程(节自 /code/chapter9/szomb2.c
#include <unistd.h>
#include <stdio.h>
void main()
{
    pid_t pid1;
    if ((pid1 = fork()) == 0)   /* 第一次 fork */
    {
        printf("child[%d]\n", getpid());
        if ((pid1 = fork()) == 0)   /* 第二次 fork */
        {
            printf("child[%d]\n", getpid());
            sleep(20);
            exit(0);        /* 第二次创建的子进程退出 */
        }
        exit(0);            /* 第一次创建的子进程退出 */
    }
    waitpid(pid1, 0, 0);
    printf("parent[%d]\n", getpid());
    sleep(60);
}
编译代码 9-13
# make szomb2
        cc -O -o szomb2 szomb2.c
后台运行程序 szobm2 ,并在子进程结束前,运行命令查询进程情况:
# ./szomb2&
10731
# child[10732]
child[10733]
parent[10731]
# ps -ef|grep szomb2
    root 10731 10449  0 20:32:19   ttyp0    00:00:00 ./szomb2
    root 10733     1  0 20:32:19   ttyp0    00:00:00 ./szomb2
上例中,进程 10733 的父进程标识号已经更改为 1 ,即已经由系统进程 init (标识号为 1 )托管。
 
相关文章:
封面          前言        目录         策划         作者
动态库        变长参数    文件锁       外设         僵死进程
 

你可能感兴趣的:(c,unix,C语言编程,Unix编程)