美文网首页
fork wait 孤儿与僵尸

fork wait 孤儿与僵尸

作者: xuefeng_apple | 来源:发表于2020-05-02 10:36 被阅读0次

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

相关文章

  • fork wait 孤儿与僵尸

    1- fork and wait 例子1:父进程----》 子进程1----》 子进程2 可以看到,两个子进程具有...

  • 操作系统常考

    0. 僵尸进程/孤儿进程 一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpi...

  • 示例说明僵尸进程的危害及解决方法

    简述 首先简要说明下僵尸进程和孤儿进程的概念(前提都是父进程调用fork产生子进程) 僵尸进程:子进程终止,父进程...

  • linux操作系统-僵尸进程与孤儿进程

    僵尸进程 概念:一个父进程利用fork创建子进程,如果子进程退出,而父进程没有利用wait或者waitpid来获取...

  • 关于如何避免僵尸进程

    1、父进程调用wait()或waitpid()函数 2、将父进程杀死或者父进程终止了,让僵尸子进程变成孤儿进程,将...

  • fork 子进程

    Fork, exec, wait and exit system call explained in Linux[...

  • 孤儿进程、僵尸进程与进程回收

    孤儿进程与僵尸进程 孤儿进程:父亲死了,子进程被init进程领养僵尸进程:子进程死了,父进程没有回收子进程的资源(...

  • Linux--fork与wait

    fork与exec 在Linux中,都是通过fork与vfork系统调用来创建子进程,并且在fork完之后,通常会...

  • 孤儿进程与僵尸进程

    孤儿进程与僵尸进程[总结] 1、前言 之前在看《unix环境高级编程》第八章进程时候,提到孤儿进程和僵尸进程,一直...

  • 僵尸进程处理方案

    僵尸进程介绍 Z(zombie)-僵尸进程(子进程终止,父进程没有wait子进程) 僵尸进程产生原因 僵尸进程是当...

网友评论

      本文标题:fork wait 孤儿与僵尸

      本文链接:https://www.haomeiwen.com/subject/jwzhghtx.html