繁体   English   中英

fork()输出中的混乱

[英]Confusion in the output of fork()

过去几天,我一直在学习fork()函数,并进行了一些实验以了解它的实际工作方式。 这样做的时候,我浏览了我没看懂的这段有趣的代码。 这是代码:

int main(int argc, char *argv[])

{
int p,m;
    p = getppid();
    printf("%d\n",p);

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
}



return 0;
}

输出为:

$./a.out
6117
6460
1
user@ubuntu:~/forkbomb$ 1
1
1
1
1
1
1
1
1
1
1
1
6473

如果您向我解释,为什么init的pid是1出现在输出中,对您真是太好了。 如果有帮助,我想澄清一下,我试图从给定的过程中创建5个过程。 那么,能否请您告诉我正确的做法呢? 谢谢

父级首先打印其父级的PID。 然后继续分叉四个子项(C1..4),然后退出。

C1打印其父PID,然后继续派生自己的三个子PID。 C2打印其父PID,然后继续派生自己的两个孩子。 C3打印其父PID ...

每个派生的子代在创建它的if块之后继续运行,因此将创建很多子代。

当父进程退出时,子进程将重新绑定到具有进程ID 1 init 每次运行的确切输出将有所不同,具体取决于孩子安排时间和方式以及父母退出的确切时间。

如果只想创建五个流程,请确保子流程完成后退出!

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
    exit(0);
}

如果要让父项等待其子项在退出自身之前全部完成,则应考虑使用wait函数族。

如果子进程的父进程在该子进程之前退出或死亡,则该子进程称为孤立进程,并由init 这意味着子代的PPID(父PID)将更改为1。这解释了您的输出,因为它来自getppid()

为了解释显示的行数,让我们对代码行进行编号:

 1  int p,m;
 2      p = getppid();
 3      printf("%d\n",p);
 4  
 5  if(fork() == 0) {
 6      p = getppid();
 7      printf("%d\n",p);
 8  }
 9  
10  if(fork() == 0) {
11      p = getppid();
12      printf("%d\n",p);
13  }
14  
15  if(fork() == 0) {
16      p = getppid();
17      printf("%d\n",p);
18  }
19  
20  if(fork() == 0) {
21      p = getppid();
22      printf("%d\n",p);
23  }

现在,让我们计算执行每个printf()所有进程。 第3行的printf()显然仅由原始父进程执行。 第7行的printf()仅由原始父进程的第一个子进程执行,因为fork()在该子进程中返回0。 现在,第9行有两个过程:原始父级和第一个子级。 他们两个都派生了他们的两个孩子(即,原始父级的第二个孩子和原始父级的第一个孩子的第一个孩子printf()在第12行执行printf() 。第4行到达第14行(原始父级) ,它既是孩子又是原父母的第一个孩子的第一个孩子)。 它们全都在第15行产生一个子级,所有四个子级在第17行执行printf() 。多达18个进程到达第19行。每个分支和最年轻的8个结果子级执行最后的printf()在第22行。

第一个printf()执行1次。 第二个printf()执行1次。 第三次printf()执行两次。 第四个printf()执行4次。 第五次printf()执行8次。

这是总共16,并且与您的输出一致。 显示的某些PPID等于1,表示给定的父级执行得太快,以至于子级在到达给定的printf()之前被init所采用。 其他大于1表示在子进程中达到printf()时,给定进程的父进程仍在运行。 程序的多次执行极有可能导致输出有所不同。

因此,您不会创建4个子进程,而是创建15个子进程。这是由于您的子进程从产生它们的fork()返回时继续执行。 这意味着一些fork()不仅将由原始父级执行,还将由其子级执行,从而创建一系列新进程。 如果只想创建4个子代,则应确保仅在父代中发生剩余的分叉。

您错过的是,当您进行分叉时,有两个进程具有相同的代码副本,从您分叉的位置开始。

父级返回孩子的pid,子级返回0。 因此,您要分叉16个进程(4个阶乘),因为在每个分叉处,您都会使进程数加倍。

如果在末尾添加sleep()以确保父进程挂起足够长的时间,则您将在子进程中获得实际的父pid(只需在返回前添加sleep(2))。

我的输出是:

> ./x
19291
21686
21686
21687
21688
21687
21687
21688
21689
21691
21690
21689
21695
21686
21686
21694

首先, 1来自已经退出的父进程。 父级然后成为系统初始化过程1

如果您也对1 s的数量感到烦恼:初始过程分叉4个子节点,此分叉的第一个子节点3,有两个子节点分别分叉2,三个子节点分叉1,而四个子节点不分叉。进一步分叉。 总共1 + 1 + 4 + 3 + 2 + 1 + 4 = 16个进程。

该程序将在四个fork()部分中创建1 + 2 + 4 + 8 = 15个进程(如果加上原始的16个)。 也许您想做的是这样的:

if(fork() == 0) {
    p = getppid();
    printf("%d\n",p);
} else
    return 0;

如果其父项不存在,getppid()将返回1。 由于我们不知道系统如何安排这些流程,因此您可以在程序中看到这种情况。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM