2012-01-04 107 views
2
#include <stdio.h> 
    #include <unistd.h> 
    int main() 
    { 
     fork(); 
     fork() && fork() || fork(); 
     fork(); 

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

它会导致难以理解如何计算执行程序后产生的进程数? 帮我看看。fork()系统调用c

平台--UBUNTU 10.04

+5

为什么不从编译和运行开始,看看有多少“分叉”消息? – 2012-01-04 12:37:06

+4

是功课吗?没有理智的人会写'fork()&& fork()||叉()'。你可以拆分这一行,并添加更多的调试输出。 – ThiefMaster 2012-01-04 12:39:05

+1

我已经编译了很多次,每次都得到不同的答案...看到这里http://ideone.com/CXlkR – 2012-01-04 12:50:54

回答

8

让我们跟随叉树,假设没有叉的失败

fork();

现在我们有两个过程,到目前为止,不管是谁的孩子,谁的父母,给他们打电话p1和p2

fork()的

这两项工艺菌种另一个孩子,所以我们有4个过程,其中两个(P3,P4),结果是零,另外两个(P1和P2)是非零

&& fork() 

p1和p2再次分叉,给出p5和p6,总共有6个过程。在p1和p2中,&&的计算结果为true,因此它们不会在此行再次分叉。为P3,P4,P5,P6,所述&&评估为假,所以他们叉

   || fork(); 

这里,产卵四个新的工艺,给出总共6 + 4 = 10。

fork();

每一次的10个进程叉

,使得20

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; 
} 
+0

你可能是对的,但这并不能真正回答这个问题。 – 2012-01-04 12:44:37

+0

嘿,慢下来!你显然没有阅读我的答案。在评论中,有执行或未执行的子进程的数量。我想回答他的问题。 – 2012-01-04 12:48:56

1

保存文件,说的那样fork-count.c。然后用gcc fork-count.c -o fork-count进行编译。然后你可以运行它并用./fork-count | wc -l来统计输出的行数。

+0

我已经编译了很多次,但它给出了不同的结果。 – 2012-01-04 12:54:41

+0

你是说你可以连续多次运行该程序并获得不同的结果? – 2012-01-04 12:58:21

+0

阅读以上评论plz。 – 2012-01-04 13:00:57

3
fork(); 

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

||&&是逻辑运算符。

如果操作的结果是左手操作数的评价后知道,他们需要短路(即不计算右边操作数):

  • ||操作其右操作数是没有评估,如果它的左操作!= 0
  • &&操作其右操作数是不是如果leftt操作评估是== 0
0

我发现这个问题on Geeks for Geeks的正确解释:

叉()系统调用创建子进程的不断增长的二叉树的叶子。如果我们调用fork()两次,它会产生22 = 4个进程。所有这4个过程都构成了二叉树的叶子。一般来说,如果我们是level 1,并且fork()无条件地调用,我们将在level(l + 1)处有2l个进程。它相当于级别为(l + 1)的二叉树中最大子节点的数量。

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

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

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

在AND的情况下(& &),在评估左操作数之后,只有在左操作数评估为非零时才评估右操作数。在OR(||)的情况下,在评估左操作数之后,仅当左操作数评估为零时才评估右操作数。

叉的返回值():

叉的手册页()引用的返回值以下摘录,

“如果成功,子进程的PID在父返回,并且在孩子中返回0。失败时,-1返回父进程,没有创建子进程,并且适当地设置了errno。“

PID就像进程句柄一样,表示为unsigned int。我们可以得出结论,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 前两个叉()调用被称为无条件。

在0级,我们只有主进程。主(图中的m)将创建子C1,两者都将继续执行。孩子们的创作顺序越来越高。

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

在等级2,由于fork() - B由m和C1执行,所以我们有m和C1作为父母,C2和C3作为孩子。

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

在3级,我们有m,C1,C2,C3作为跑步过程,C4,C5作为孩子。该表达式现在被简化为((B & & C)|| D),并且此时(C)的值是显而易见的。在父母中,它是非零的,在儿童中是零。因此,父母知道总体结果B & & C || D,将跳过执行fork() - D。因为在子节点(B & & C)评估为0时,它们将执行fork()-D。我们应该注意到,在第2级创建的子节点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个进程。