0

这是一个代码,我一个接一个地使用 2 个 fork() 系统调用 - 它实际上是如何工作的?

 #include <unistd.h>
 #include <iostream.h>
 using namespace std;

 int main()
 {
    cout << "0. I am process " << getpid() << endl;
    (void) fork();
    cout << "1. I am process " << getpid() << endl;
    (void) fork();
    cout << "2. I am process " << getpid() << endl;
}

我得到的输出为:
0.我是进程 27701
1.我是进程 25915 1.
我是进程 27701
2.我是进程 27781
2.我是进程 26170
2.我是进程 27701

这是我使用 3 个 fork 系统调用的下一个程序,我如何获得这样的输出?如果我要手动解决此代码,逻辑是什么?

#include <unistd.h>
#include <iostream>
using namespace std;

int main()
{
    cout << "0. I am process " << getpid() << endl;
    (void) fork();
    cout << "1. I am process " << getpid() << endl;
    (void) fork();
    cout << "2. I am process " << getpid() << endl;
    (void) fork();
    cout << "3. I am process " << getpid() << endl;
}

在这里我得到的输出为:
0.我是进程 27116
1.我是进程 26147
2.我是进程 27371
2.我是进程 26147
3.我是进程 24416
3.我是进程 27371
3.我是进程 27508
3 .我是进程26147
1.我是进程27116
2.我是进程21406
2.我是进程27116
3.我是进程27369
3.我是进程21406
3.我是进程26752
3.我是进程27116

4

4 回答 4

5

fork()每次调用时都以相同的方式工作。创建一个新进程作为当前进程的精确副本,并且两者都继续执行,就好像它们都刚刚从fork()函数调用中返回一样,只是返回值不同。在您的情况下,您丢弃了该返回值,因此它们只是相同的过程。

让我们为您的第一个示例绘制一张图片。我刚刚运行的示例输出(因为您在问题中输入的输出不完整):

0. I am process 25597
1. I am process 25597
2. I am process 25597
1. I am process 25598
2. I am process 25599
2. I am process 25598
2. I am process 25600

您从 PID 25597 的单个进程开始。它打印该0行,然后分叉。这产生了两个过程:

            25597          # prints "0"
             /\
            /  \
           /    \
         25597 25598       # both print "1"

到目前为止,一切都很好。现在这两个新进程都fork()再次调用。完整的树最终看起来像这样:

                   25597
                    /\
                   /  \
                  /    \
                 /      \
                /        \
             25597      25598       # both print "1"
              /\          /\
             /  \        /  \
            /    \      /    \
         25597  25599 25598 25600   # all four print "2"

不幸的是,无法从输出中猜出 25599 和 25600 的实际位置 - 它们也可能反过来。

对于您的 3-fork()示例,您只需要做同样的事情,但它会在图中具有另一个级别 - 您最终将有 8 个进程,每个进程都打印“3”行。

于 2013-07-17T18:43:57.453 回答
1

你的程序完全错误。你永远不应该忽略fork.

阅读Advanced Linux Programming一书和fork(2)手册页(仔细阅读该页数次)。

典型的代码应该是:

  pid_t pid1 = fork();
  if (pid1<0) { perror("fork1 failed"); exit(EXIT_FAILURE); }
  else if (pid1 == 0) {
     // you are in the child process
  }
  else // pid1>0 
  {  // you are in the parent process
  }

同样forpid_t pid2=fork();然后for pid_t pid3=fork();等......所以每次调用都fork应该处理fork(失败即<0子进程==0,父进程>0)结果的3种情况

原则上,您有 3 3即 27 种可能性。但是您可以及早处理失败案例,这会留下 2 3即 8。可能性

不要忘记处理fork. 您可能会降低您的进程限制(使用setrlimit (2)RLIMIT_NPROC或等效的ulimit bash 内置)以简化fork失败测试。

于 2013-07-17T18:43:25.663 回答
0

当调用 fork() 时,会创建并运行一个子进程。因此,您将在子进程中执行一次以下语句:

cout << "1. I am process " << getpid() << endl;

此外,当调用另一个 fork 时,会创建另一个运行下一个“cout”语句的子进程。但是,父进程也会运行。这也发生在第三个 fork() 上。

所有这些都发生在第一个 fork() 的子进程中。在此之后,第一个 fork 的父进程也会运行以显示您的输出。

于 2013-07-17T18:54:10.323 回答
0

只需画一棵树,其中每个根节点都是一个 fork 调用,叶节点是它后面的代码。

在第一个程序中,您的 cout<<"0..." 是父程序,在 fork 调用之后,该行之后的整个程序执行两次。因此有两个“1...”输出行。

现在在此之后还有另一个分叉调用。这次有 3 个进程正在运行(1.您调用的原始父级,2.它产生的子级 3.子级本身产生另一个孙子。)
因此有 3 个“2...”输出行。

于 2013-07-17T18:42:23.133 回答