进程——wait与waitpid、僵尸进程与孤儿进程

僵尸进程:子进程终止了,但是父进程没有回收子进程的资源PCB。使其成为僵尸进程

孤儿进程:父进程先与子进程结束了,使得子进程失去了父进程,这个时候子进程会被1号进程init进程领养,成为孤儿进程

为了防止上面两种情况,我们应当在父进程结束之前一定要回收子进程的所有资源

所以出现了wait和waitpid

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);

status是一个传出参数。
waitpid的pid参数选择:
< -1 回收指定进程组内的任意子进程
= -1 回收任意子进程
= 0  回收和当前调用waitpid一个组的所有子进程
> 0  回收指定ID的子进程

一个进程结束的时候,会关闭所有的文件描述符,释放所有的内存空间,但是他的PCB仍然存在,保存着子进程的一些状态信息,如果进程正常退出,保存着正常退出的状态,如果非正常退出,那么保存着是哪个信号导致的该进程退出,父进程可以通过wait和waitpid查看到这些信息,并且彻底清除,我们知道shell是所有进程的父进程,在shell中可以通过 $查看退出状态编号,所以可以通过shell查看并清除,如果一个进程退出,父进程并没有调用wait和waitpid进程清除,那么就产生了僵尸进程,正常情况下,僵尸进程都被父进程清理了

下面写一个不正常了程序,使得父进程不结束

#include <unistd.h>
#include <stdlib.h>

int main(void)
{
    pid_t pid=fork();

    if(pid<0) {
        perror("fork");
        exit(1);
    }

    if(pid>0) { /* parent */
        while(1);
    }

    /* child */
    return 0;
}

上面中,父进程一直处于while(1)循环,使得父进程不退出,下图查看ps aux可以发现父进程状态为R,子进程状态为Z(僵尸态Zombie)

 对于wait或waitpid函数若调用成功则返回清理掉的子进程id,若调用出错则返回-1。父进程调用wait或waitpid时可能会出现一下的情况:

  1. 阻塞(如果它的所有子进程都还在运行)。
  2. 带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信息)。
  3. 出错立即返回(如果它没有任何子进程)。

上图看到了,wai成功的返回值

*******************************************************************************************

  对于wait和waitpid两个函数,有所不同的是:

  1. 如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。
  2. wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。

所以,调用wait和waitpid不仅可以获得子进程的终止信息,还可以使父进程阻塞等待子进程终止,起到进程间同步的作用。如果参数status不是空指针,则子进程的终止信息通过这个参数传出,如果只是为了同步而不关心子进程的终止信息,可以将status参数指定为NULL。

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 #include <sys/types.h>
 5
 6 int main(void)
 7 {
 8     pid_t pid,pid_c;
 9
10     int n = 10;
11     pid = fork();
12
13     if(pid > 0 )
14     {/* in parent */
15         while(1)
16         {
17             printf("I am parent %d\n",getpid());
18             //wait是一个阻塞函数,等待回收子进程资源,如果没有子进程,wait返回-1
19             pid_c = wait(NULL);
20             printf("wait for child %d\n",pid_c);
21             sleep(1);
22         }
23     }
24     else if(pid == 0)
25     {/* in child */
26         printf("I am child %d\n",getpid());
27         sleep(10);
28     }
29
30     return 0;
31 }
32
33
34 运行结果:
35 I am parent 4797
36 I am child 4798
37 wait for child 4798
38 I am parent 4797
39 wait for child -1
40 I am parent 4797
41 wait for child -1
42 I am parent 4797

孤儿进程

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

int main(void)
{
    pid_t pid;
    int n=10;
    pid = fork();
    if(pid > 0)
    {//创建完之后父进程就退出了
        printf("I am parent\n");
        exit(0);
    }
    else if(pid == 0)
    {//此时父进程退出,子进程被init程序接管,该进程的父进程号变成1
        while(n--)
        {
            printf("I am %d, my parent is %d\n",getpid(),getppid());
            sleep(1);
        }
    }
    else
    {
        perror("fork");
        exit(-1);
    }
    return 0;
}

运行结果:
I am 4813, my parent is 1
I am 4813, my parent is 1
I am 4813, my parent is 1
I am 4813, my parent is 1
I am 4813, my parent is 1
I am 4813, my parent is 1

waitpad

 1 #include <sys/types.h>
 2 #include <sys/wait.h>
 3 #include <unistd.h>
 4 #include <stdio.h>
 5 #include <stdlib.h>
 6
 7 int main(void)
 8 {
 9     pid_t pid;
10     pid = fork();
11     if (pid < 0)
12     {
13         perror("fork failed");
14         exit(1);
15     }
16
17     if (pid == 0)
18     {//in child
19         int i;
20         for (i = 3; i > 0; i--) {
21             printf("This is the child %d\n",getpid());
22             sleep(1);
23         }
24         exit(3);//返回3,运行时可以看到
25         //子进程睡眠3秒之后就退出了
26     }
27
28     else
29     {//in parent
30         int stat_val;
31         waitpid(pid, &stat_val, 0);//以阻塞方式等待回收子进程,第三个参数0,表示阻塞方式
32         if (WIFEXITED(stat_val))//正常退出
33             printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
34         else if (WIFSIGNALED(stat_val))//查看被什么信号关闭
35     printf("Child terminated abnormally, signal %d\n", WTERMSIG(stat_val));
36     }
37     return 0;
38 }
时间: 2024-10-04 16:28:35

进程——wait与waitpid、僵尸进程与孤儿进程的相关文章

孤儿进程 &amp;&amp; 僵尸进程

background: unix: 每个子进程退出,内核释放该进程所有资源,打开的文件,占用的内存 保留的信息:the process ID,the termination status of the process,the amount of CPU time taken by the process 父进程用wait()/waitpid()释放子进程的保留信息 父进程不调用wait()/waitpid()进程号一直被占用,系统所能提供的进程号有限,没有可用的进程号导致系统不能产生新的进程 Z

孤儿进程和僵尸进程

孤儿进程和僵尸进程 一.定义:什么是孤儿进程和僵尸进程 僵尸进程:一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出.这个子进程就是僵尸进程. 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作. 僵尸进程将会导致资源浪费,而孤儿则不会. 子进程持续10秒钟的僵尸状态(EXIT_ZOMBIE)------------------------------

Linux-进程描述(3)之进程状态僵尸进程与孤儿进程

进程状态 进程状态反映进程执行过程的变化.这些状态随着进程的执行和外界条件的变化而转换.为了弄明正正在运行的进程是什么意思,我们需要知道进程的不同状态.一个进程可以有多个状态(在Linux内核中,进程有时候也叫做任务).下面的状态在 fs/proc/array.c 文件中定义: /* * The task state array is a strange "bitmap" of * reasons to sleep. Thus "running" is zero,

python学习笔记——孤儿进程和僵尸进程

1 基本概述 1.1 孤儿进程和僵尸进程 父进程创建子进程后,较为理想状态是子进程结束,父进程回收子进程并释放子进程占有的资源:而实际上,父子进程是异步过程,两者谁先结束是无顺的,一般可以通过父进程调用wait()或waitpid()语句来等待子进程结束再退出. 孤儿进程:父进程结束后还有基于该父进程创建的子进程(一个或多个)尚没有结束,此时的子进程称之为孤儿进程:孤儿进程将被init进程(进程树中除了init都有父进程)接受,也就意味着init进程负责孤儿进程完成状态收集工作.一般而言,ini

快速理解孤儿进程和僵尸进程

下面是我大约11年前在读APUE(<Unix环境高级编程>)对孤儿进程和僵尸进程的理解,为了便于记忆,采用打比方的方式予以解释. (当然不一定精准,后面我会贴出wikipedia上的专业解释.) 操作系统OS好比一个公司,公司的CEO就是init进程. 任何一个子进程都有父进程,就好比任何一个人都有爹. 这里假定子进程为小明,父进程为小明的爸爸. init进程作为OS公司的CEO,是小明的爷爷(注:小明的爸爸很可能是CEO的第N代后人,N>=1,这里假定N=1). 任何一个进程在退出之后

僵尸进程、孤儿进程

僵尸进程:子进程结束了,父进程还在,并且父进程没有处理子进程的结束状态,导致子进程没有人管理,成为僵尸.危害是,虽然没有占用很多内存空间,但是占用了进程号,进程表,占用太多了,其他进程就没有进程号分配,无法启动. 孤儿进程:子进程还没有结束,父进程先挂了,这时候子进程就成了孤儿进程.但是没事,会有托儿所init进程(进程号为1)管理子进程,对子进程占用的资源进行释放. 使用python模拟僵尸进程和孤儿进程: 原文地址:https://www.cnblogs.com/shengulong/p/1

【APUE】孤儿进程与僵死进程

基本概念: 在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程.子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态. 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作. 僵尸进程:一个进程

fork()、僵死进程和孤儿进程

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作. 僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中.这种进程称之为僵死进程. #include <stdio.h> #include <iostream> #include "unistd.

孤儿进程

父进程运行结束,但子进程还在运行(未运行结束)的子进程就称为孤儿进程(Orphan Process).孤儿进程最终会被 init 进程(进程号为 1 )所收养,并由 init 进程对它们完成状态收集工作. 孤儿进程是没有父进程的进程,为避免孤儿进程退出时无法释放所占用的资源而变为僵尸进程(什么是僵尸进程,请看<僵尸进程>),进程号为 1 的 init 进程将会接受这些孤儿进程,这一过程也被称为"收养".init 进程就好像是一个孤儿院,专门负责处理孤儿进程的善后工作.每当出

Linux进程学习(孤儿进程和守护进程)

孤儿进程和守护进程 通过前面的学习我们了解了如何通过fork()函数和vfork()函数来创建一个进程.现在 我们继续深入来学习两个特殊的进程:孤儿进程和守护进程 一.孤儿进程 1.什么是 孤儿进程如果一个子进程的父进程先于子进程 结束, 子进程就成为一个孤儿进程,它由 init 进程收养,成为 init 进程的子进程.2.那么如何让一个进程变为一个孤儿进程呢?我们可以先创建一个进程,然后杀死其父进程,则其就变成了孤儿进程.pid =  fork();if(pid > 0) {