fork中的fork()系统调用

时间:2012-01-04 12:36:03

标签: c unix fork

    #include <stdio.h>
    #include <unistd.h>
    int main()
    {
       fork();
       fork() && fork() || fork();
       fork();

     printf("forked\n");
     return 0;
    }

难以理解如何计算执行程序后产生的进程数? 帮我看看。

平台--UBUNTU 10.04

5 个答案:

答案 0 :(得分:9)

让我们按照fork-tree,假设没有任何forks失败

  

叉();

现在我们有两个过程,到目前为止,无论是谁的孩子和谁是父母,都称他们为p1和p2

  

fork()的

这两个进程都生成另一个子进程,所以我们有4个进程,其中两个进程(p3,p4)结果为零,其他两个进程(p1和p2)非零

   && fork()
再次p1和p2分叉,给出p5和p6,共计6个进程。在p1和p2中,&&的计算结果为true,因此它们不再在此行中进行分叉。对于p3,p4,p5,p6,&&的计算结果为false,所以它们是fork

              || fork();

这里,产生了四个新进程,共计6 + 4 = 10。

  

叉();

10个进程中的每一个再次分叉,成为20个。

答案 1 :(得分:3)

fork();

fork系统调用返回一个整数:父进程中进程的PID和子进程中的0。如果发生错误,则不会创建任何进程并返回-1。

||&&是逻辑运算符。

如果在评估左操作数后知道运算符的结果,则需要它们短路(即不评估右操作数):

  • 对于||运算符,如果其左操作数为!= 0,则不评估其右操作数。
  • 对于&&运算符,如果其leftt操作数为== 0,则不评估其右操作数

答案 2 :(得分:2)

你不应该像这样使用fork()。决不。然而,在现实生活中你不需要这样做。 如何使用它:

int main() {
    /* code */
    pid_t pid = fork();
    if (pid < 0) {
        /* error, no child process spawned */
    }
    if (pid > 0) {
        /* we are the parent process, pid is the process ID of the ONE child process spawned */
    }
    /* else, we are the child process, running exactly one command later the fork() was called in the parent. */
    /* some more code */
    return 0;
}

答案 3 :(得分:1)

保存文件,例如fork-count.c。然后用gcc fork-count.c -o fork-count编译它。然后,您可以运行它并使用./fork-count | wc -l计算输出行数。

答案 4 :(得分:0)

我找到了这个问题的正确解释on Geeks for Geeks

fork()系统调用spawn进程作为增长二叉树的叶子。如果我们两次调用fork(),它将产生22 = 4个进程。所有这四个过程形成了二叉树的叶子。一般来说,如果我们是level l,而fork()是无条件调用的,那么我们将在level(l + 1)处有2l个进程。它等同于二级树中级别(l + 1)的最大子节点数。

作为另一个例子,假设我们无条件地调用了3次fork()调用。我们可以使用具有3个级别的完整二叉树来表示生成的进程。在级别3,我们将有23 = 8个子节点,这对应于正在运行的进程数。

关于C / C ++逻辑运算符的说明:

逻辑运算符&amp;&amp;比||具有更多的优先级,并且具有从左到右的关联性。执行左操作数后,将估计最终结果,并且右操作数的执行取决于左操作数的结果以及操作类型。

在AND(&amp;&amp;)的情况下,在评估左操作数之后,仅当左操作数计算为非零时才评估右操作数。在OR(||)的情况下,在评估左操作数之后,仅当左操作数的计算结果为零时才会计算右操作数。

fork()的返回值:

fork()的手册页引用了以下关于返回值的摘录

“成功时,子进程的PID在父进程中返回,并在子进程中返回0。失败时,在父项中返回-1,不创建子进程,并正确设置errno。“

PID就像进程的句柄,表示为unsigned int。我们可以得出结论,fork()将在父级中返回非零,在子级中返回零。让我们分析一下该计划。为了便于表示,请标记每个fork(),如下所示,

     #include <stdio.h>
     int main()
      {
       fork(); /* A */
      (       fork()  /* B */ &&
      fork()  /* C */ ) || /* B and C are grouped according to precedence */
      fork(); /* D */
      fork(); /* E */

      printf("forked\n");
      return 0;
     }

enter image description here 前两个fork()调用是无条件调用的。

在0级,我们只有主要过程。 main(图中的m)将创建子C1并且两者都将继续执行。这些孩子的编号越来越多。

在级别1,我们运行m和C1,并准备执行fork() - B.(注意,B,C和D被命名为&amp;&amp;和||运算符的操作数)。初始表达式B将在此级别运行的每个子进程和父进程中执行。

在第2级,由于fork() - B由m和C1执行,我们将m和C1作为父级,C2和C3作为子级。

fork() - B的返回值在父级中为非零,在子级中为零。由于第一个运算符是&amp;&amp;,因为零返回值,子C2和C3不会执行下一个表达式(fork() - C)。父进程m和C1将继续使用fork() - C.子C2和C3将直接执行fork() - D,以评估逻辑OR运算的值。

在第3级,我们有m,C1,C2,C3作为运行过程,C4,C5作为子项。表达式现在简化为((B&amp; C)|| D),此时(B&amp; C)的值是显而易见的。在父母中它是非零的,在儿童中它是零。因此,父母意识到整体B&amp;&amp ;;的结果。 C || D,将跳过fork() - D的执行。因为,在孩子(B&amp; C)中评估为零,他们将执行fork() - D.我们应该注意到在C2级创建的子C2和C3 ,也将如上所述运行fork() - D.

在第4级,我们将m,C1,C2,C3,C4,C5作为运行进程,C6,C7,C8和C9作为子进程。所有这些进程都无条件地执行fork() - E,并生成一个子进程。

在第5级,我们将运行20个进程。该程序(在Ubuntu Maverick,GCC 4.4.5上)打印了“分叉”20次。一旦由父母(主)和孩子休息。总的来说,将会产生19个流程。