#include <stdio.h>
#include <unistd.h>
int main()
{
fork();
fork() && fork() || fork();
fork();
printf("forked\n");
return 0;
}
难以理解如何计算执行程序后产生的进程数? 帮我看看。
平台--UBUNTU 10.04
答案 0 :(得分:9)
让我们按照fork-tree,假设没有任何forks失败
叉();
现在我们有两个过程,到目前为止,无论是谁的孩子和谁是父母,都称他们为p1和p2
fork()的
这两个进程都生成另一个子进程,所以我们有4个进程,其中两个进程(p3,p4)结果为零,其他两个进程(p1和p2)非零
再次p1和p2分叉,给出p5和p6,共计6个进程。在p1和p2中,&& fork()
&&
的计算结果为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;
}
前两个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个流程。