从同一进程创建N个子进程,然后打印具有相关父进程的所有子进程的PID

时间:2019-05-04 10:28:08

标签: c linux fork child-process

我仍然不明白为什么pid = 11310的子进程创建pid = 11312的子进程

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


int main(){
    pid_t pid[2];
    for (int i = 0; i<2; i++){
        pid[i] = fork();
        if ( pid[i] == 0){  
            printf("[child] pid %d from [parent] pid %d\n",getpid(),getppid());
        }
    }
}

我的期望:

[child] pid 11310 from [parent] pid 11309
[child] pid 11311 from [parent] pid 11309

但是实际结果:

[child] pid 11310 from [parent] pid 11309
[child] pid 11311 from [parent] pid 11309
[child] pid 11312 from [parent] pid 11310

1 个答案:

答案 0 :(得分:1)

fork()通过复制调用过程来创建子过程,并将其从被调用点一分为二。子进程和父进程在单独的内存空间中运行 1)。在fork()时,两个存储空间的内容相同。也就是说,fork()时子进程中变量的值与父进程中的值相同。

for循环的第一次迭代中:

pid[i] = fork(); 
// this will create child process and both parent and child process proceed with next statement

if ( pid[i] == 0){ // only child process will enter to this if block
        printf("[child] pid %d from [parent] pid %d\n",getpid(),getppid());
}

输出显示:

[child] pid 11310 from [parent] pid 11309

在执行for循环主体之后,由于i,在父进程和子进程地址空间中循环控制变量i++的值都会增加。

因此,在第二次迭代中,父级和子级地址空间中i的值均为1

现在,父(PID: 11309)和子(PID: 11310)都将执行for循环主体,并且两者都将创建一个子进程。这就是子进程(PID: 11310)创建另一个子(PID: 11312)的原因。

             11309-----    --|
               |      |      |---------> First iteration
             11310    |    --|   --|
               |      |            |---> Second iteration
             11312  11311        --|

在第三次迭代中,在所有i进程中,2的值将为4,循环条件i<2将导致false,并且所有该过程将退出。

您的代码中存在一个严重问题-如果父进程完成运行并在子进程之前退出会发生什么?
在这种情况下,子进程将变为orphan process,并且您可能将父PID设置为1而不是原始父进程ID,因为孤立进程可能会重新绑定为 init 进程,通常分配给PID 1

要解决此问题,必须在退出前为其所有子进程设置父wait

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

int main(void) {
    pid_t pid;

    // You can take number of child process to be create as input from user

    for (int i = 0; i < 2; i++) {
        pid = fork();
        if (pid == 0) {
            printf("[child] pid %d from [parent] pid %d\n", getpid(), getppid());
            break;
        }
    }

    if (pid != 0) {
        int cpid;
        int status;
        while ((cpid = wait(&status)) > 0)
            printf("Parent (%d): child (%d) exited with status 0x%.4x\n", (int)getpid(), cpid, status);
    }

    return 0;
}

1)有一个名为写时复制的概念,这是对页表进行设置的一种优化,以便父级和子级进程开始共享所有相同的内存,并且在需要时,仅复制由任一进程写入的页面。这意味着父进程和子进程都共享同一数据的副本,并且一旦它们中的任何一个进行写操作,就会进行复制,并且一个进程的内存中的任何更改在另一个进程中都不可见。