【问题标题】:How do 2 or more fork system calls work?2 个或更多 fork 系统调用如何工作?
【发布时间】:2013-07-16 11:12:22
【问题描述】:

这是一个代码,我一个接一个地使用 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

【问题讨论】:

  • 关于fork 在这种复杂情况下如何工作的问题有很多。画个图就好了。
  • 我需要逻辑来画图!如果可能的话,请把逻辑解释给第一个程序,如果我理解了,我会自己尝试第二个程序。
  • 你的第一个程序应该输出 4 批标记为2 的行,有 4 个不同的 PID。 25915 的输出发生了什么变化?

标签: linux unix system-calls fork


【解决方案1】:

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”行。

【讨论】:

  • 谢谢!你解释得太简单了,我一直在互联网上徘徊只是为了找到一个简单的解释!
【解决方案2】:

你的程序完全错误。你应该永远不要忽略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
  }

同样适用于pid_t pid2=fork();,然后是pid_t pid3=fork(); 等...... 所以对fork的每次调用都应该处理fork的3种结果(失败即&lt;0,子进程==0,父进程&gt;0

原则上你有 33 即 27 种可能性。但是您可以及早处理失败案例,留下 23 即 8. 可能性

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

【讨论】:

  • 我放这个测试代码是为了理解 fork() 在一个接一个地使用时是如何工作的,下次我在真正的程序上工作时会记住你的更正。谢谢。
【解决方案3】:

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

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

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

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-01
      • 2015-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-08
      相关资源
      最近更新 更多