2个或更多fork系统调用如何工作?

时间:2013-07-17 18:34:44

标签: linux unix system-calls fork

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

我得到的输出为:
我是程序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;
}

这里我得到的输出为:
我是流程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 个答案:

答案 0 :(得分: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”行。< / p>

答案 1 :(得分: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
  }

同样适用于pid_t pid2=fork();,然后适用于pid_t pid3=fork();等...... 因此,对fork的每次调用都应该处理fork的结果的3个案例(失败即<0,子进程==0,父进程>0

原则上,你有3 3 ,即27种可能性。但你可以尽早处理失败的情况,即2 3 ,即8种可能性

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

答案 2 :(得分:0)

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

在第一个程序中,你的cout&lt;&lt;“0 ...”是父程序,在fork调用之后,该行之后的整个程序执行两次.Hen两个“1 .. 。“输出线。

在此之后还有另一个叉号。这次有3个进程在运行(1.你调用的原始父进程,2。它生成的子进程3.子进程产生了另一个孙子。)因此3“2 ......”输出行。

答案 3 :(得分:0)

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

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

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

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