fork wait 孤儿与僵尸

1- fork and wait

例子1:
父进程
----》 子进程1
----》 子进程2

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void)
{
        pid_t pid_1, pid_2;

        if(0 == (pid_1 = fork())) {
                printf("I'm child1. my pid = %d, pid_father = %d\n", getpid(), getppid());
        } else {
                if(0 == (pid_2 = fork())) {
                        printf("I'm child2. my pid = %d, pid_father = %d\n", getpid(), getppid());
                } else {
                        printf("I'm father. my pid = %d, first wait = %d, second wait = %d, pid_1 = %d, pid_2 = %d\n", getpid(), wait(NULL), wait(NULL), pid_1, pid_2);
                }
        }

        return 0;
}

可以看到,两个子进程具有相同的父进程,而父进程的两次wait()分别得到了两个子进程的pid。
fork()在子进程中返回0,而在父进程中返回子进程的pid。pid_1和pid_2的值说明了这点

执行结果:

I'm child1. my pid = 17507, pid_father = 17506
I'm child2. my pid = 17508, pid_father = 17506
I'm father. my pid = 17506, first wait = 17508, second wait = 17507, pid_1 = 17507, pid_2 = 17508

例子2: 共享内存, 子子进程11 与父进程通信
父进程
----》 子进程1----》 子子进程11

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/shm.h>
#include <stdlib.h>

int main(void)
{
        int shmid = 0;
        int *shmbuf = NULL;

        if((shmid = shmget(777, sizeof(int), 0666 | IPC_CREAT)) < 0) {
                perror("shmget");
                exit(-1);
        }
        if((shmbuf = shmat(shmid, NULL, 0)) < 0) {
                perror("shmat");
                exit(-1);
        }

        if(0 == fork()) {
                if(0 == fork()) {
                        printf("I'm the child of child1. my pid = %d, pid_father = %d\n", getpid(), getppid());
                        *shmbuf = getpid();
                } else {
                        printf("I'm child1. my pid = %d, pid_father = %d, pid_my_child = %d\n", getpid(), getppid(), wait(NULL));
                }
        } else {
                printf("I'm father. my pid = %d, pid_my_child = %d, ", getpid(), wait(NULL));
                printf("pid_child_of_child1 = %d\n", *shmbuf);

                if(shmdt(shmbuf) < 0) {
                        perror("shmdt");
                        exit(-1);
                }
                if(shmctl(shmid, IPC_RMID, NULL) < 0) {
                        perror("shmctl");
                        exit(-1);
                }

        }

        return 0;
}

结果:

I'm the child of child1. my pid = 17521, pid_father = 17520
I'm child1. my pid = 17520, pid_father = 17519, pid_my_child = 17521
I'm father. my pid = 17519, pid_my_child = 17520, pid_child_of_child1 = 17521

例子3

#include <sys/types.h>
#include <wait.h>
int wait(int *status)

函数功能是:父进程一旦调用了wait就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。

1,WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。

2, WEXITSTATUS(status) 当WIFEXITED返回非零值时,我们可以用这个宏来提取子进程的返回值,如果子进程调用exit(5)退出,WEXITSTATUS(status) 就会返回5;如果子进程调用exit(7),WEXITSTATUS(status)就会返回7。

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
#include <errno.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{

  int count = 0;
  pid_t pid = fork();
  int status = -1;
  
  if(pid<0)
  {
    printf("fork error for %m\n",errno );
  }else if(pid>0)
  {
    printf("this is parent ,pid = %d\n",getpid() );
    wait(&status);//父进程执行到此,马上阻塞自己,直到有子进程结束。当发现有子进程结束时,就会回收它的资源。
    
  }else
  {
    printf("this is child , pid = %d , ppid = %d\n",getpid(),getppid() );
    int i;
    
    for (i = 0; i < 10; i++) {
      count++;
      sleep(1);
      printf("count = %d\n", count)  ;
      
    }
    exit(5);
    
  }
  printf("child exit status is %d\n", WEXITSTATUS(status));//status是按位存储的状态信息,需要调用相应的宏来还原一下
  printf("end of program from pid = %d\n",getpid() );
}

运行结果:

this is parent ,pid = 17576
this is child , pid = 17577 , ppid = 17576
count = 1
count = 2
count = 3
count = 4
count = 5
count = 6
count = 7
count = 8
count = 9
count = 10
child exit status is 5
end of program from pid = 17576

2- 孤儿与僵尸

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

2.1问题及危害
僵尸进程:
如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

孤儿进程:
孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上, init循环回收, 因此孤儿进程并不会有什么危害。

任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个 子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。 如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。

2.2-僵尸进程解决办法
子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>

static void sig_child(int signo);

int main()
{
    pid_t pid;
    //创建捕捉子进程退出信号
    signal(SIGCHLD,sig_child);
    pid = fork();
    if (pid < 0)
    {
        perror("fork error:");
        exit(1);
    }
    else if (pid == 0)
    {
        printf("I am child process,pid id %d.I am exiting.\n",getpid());
        exit(0);
    }
    printf("I am father process.I will sleep two seconds\n");
    //等待子进程先退出
    sleep(2);
    //输出进程信息
    system("ps -o pid,ppid,state,tty,command");
    printf("father process is exiting.\n");
    return 0;
}

static void sig_child(int signo)
{
     pid_t        pid;
     int        stat;
     //处理僵尸进程
     while ((pid = waitpid(-1, &stat, WNOHANG)) >0)
            printf("child %d terminated.\n", pid);
}

REF:https://blog.csdn.net/Eunice_fan1207/article/details/81387417

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345