为什么该程序打印“分叉!” 4次?
#include <stdio.h>
#include <unistd.h>
int main(void) {
fork() && (fork() || fork());
printf("forked!\n");
return 0;
}
为什么该程序打印“分叉!” 4次?
#include <stdio.h>
#include <unistd.h>
int main(void) {
fork() && (fork() || fork());
printf("forked!\n");
return 0;
}
Answers:
第fork()
一个在调用过程中返回一个非零值(称为p0),在子进程中返回0(称为p1)。
在p1中,发生短路,&&
过程调用printf
并终止。在p0中,过程必须评估表达式的其余部分。然后fork()
再次调用,从而创建一个新的子进程(p2)。
在p0中fork()
返回一个非零值,并进行短路||
,因此该过程调用printf
并终止。
在p2中,fork()
返回0,所以||的其余部分 必须评估,这是最后一个fork()
;导致为p2创建一个孩子(称为p3)。
然后printf
,P2执行并终止。
然后printf
,P3执行并终止。
printf
然后执行4 s。
&&
为零,则不计算其他操作数。在相同的逻辑上,如果a的操作数||
为1,则其余操作数不需要求值。发生这种情况是因为其余操作数无法更改逻辑表达式的结果,因此不需要执行它们,因此可以节省时间。现在更好罗纳?顺便问一个好问题,我看不出为什么要投票。您向我+1致谢。
fork()
,但是甚至不知道短路是什么。这是学校的问题吗?
一个来自main()
每个,另外三个来自每个fork()
。
注意,这三个forks()
都将被执行。您可能想看看ref:
返回值
成功完成后,fork()应将0返回给子进程,并将子进程的进程ID返回给父进程。这两个过程均应继续从fork()函数执行。否则,将-1返回给父进程,不创建任何子进程,并设置errno来指示错误。
请注意,进程ID不能为零,如规定在这里。
那么到底发生了什么?
我们有:
fork() && (fork() || fork());
因此,第一个fork()
将其非零进程ID返回给父进程,而它将向子进程返回0。这意味着逻辑表达式的第一个fork将在父进程中被评估为true,而在子进程中将被评估为false,并且由于短路评估,它将不调用其余两个fork()
s。
因此,现在我们知道至少要打印两张照片(一张来自main,一张来自1st fork()
)。
现在,fork()
将执行父进程中的2nd ,它会执行此操作,并且它将向父进程返回一个非零值,在子进程中返回一个零。
因此,现在,父进程将不会继续执行到最后一个fork()
(由于短路),而子进程将执行最后一个派生,因为第一个操作数||
为0。
因此,这意味着我们将再获得两张印刷品。
结果,我们总共得到四张印刷品。
短路
在此,短路基本上意味着,如果&&的第一个操作数为零,则不评估其他一个或多个操作数。在相同的逻辑上,如果||的操作数 为1,则其余操作数无需求值。发生这种情况是因为其余操作数无法更改逻辑表达式的结果,因此不需要执行它们,因此可以节省时间。
请参见下面的示例。
处理
请记住,父流程会创建后代流程,而后代流程又会创建其他流程,依此类推。这导致了流程的层次结构(或者可以说是一棵树)。
考虑到这一点,这是值得考虑看看这个类似的问题,以及这个答案。
描述性图像
我猜我也做了这个数字,可以提供帮助。我假设fork()
每次调用返回的pid分别为3、4和5。
请注意,有些fork()
s上方有一个红色的X,这意味着由于逻辑表达式的短路求值而未执行它们。
fork()
顶部的s不会被执行,因为运算符的第一个操作数&&
为0,因此整个表达式的结果为0,因此执行其余操作数没有本质&&
。
该fork()
底部将不会被执行,因为它的第二个操作数||
,在其第一个操作数是一个非零数字,因此表达式的结果已经被评估为真,无论第二个操作数是什么。
在下一张图片中,您可以看到流程的层次结构: 基于上图。
短路示例
#include <stdio.h>
int main(void) {
if(printf("A printf() results in logic true\n"))
;//empty body
if(0 && printf("Short circuiting will not let me execute\n"))
;
else if(0 || printf("I have to be executed\n"))
;
else if(1 || printf("No need for me to get executed\n"))
;
else
printf("The answer wasn't nonsense after all!\n");
return 0;
}
输出:
A printf() results in logic true
I have to be executed
对于所有反对者来说,这是一个合并但又不同的问题。怪SO。谢谢。
您可以将问题分解为三行,第一行和最后一行都只是使过程数加倍。
fork() && fork() || fork();
操作员正在短路,所以这是您得到的:
fork()
/ \
0/ \>0
|| fork() && fork()
/\ / \
/ \ 0/ \>0
* * || fork() *
/ \
* *
因此,这总共4 * 5 = 20处理每个打印一行。
注意:如果由于某些原因fork()失败(例如,您对进程数有一定限制),它将返回-1,然后您可以获得不同的结果。
fork() && fork() || fork();
,而这里的问题使用了fork() && (fork() || fork());
。如此处讨论的那样存在一个合并:“ meta.stackoverflow.com/questions/281729/… ”。您可能需要编辑答案,以通知将来的读者。
执行中fork() && (fork() || fork())
,会发生什么
每个fork
给定2个进程,其值分别为pid(父级)和0(子级)
第一叉:
&& (fork() || fork())
||
部件=>打印forked
|| fork()
forked
forked
forked
合计:4 forked
我喜欢已经提交的所有答案。也许,如果您在printf语句中添加了一些其他变量,则可以更轻松地了解正在发生的情况。
#include<stdio.h>
#include<unistd.h>
int main(){
long child = fork() && (fork() || fork());
printf("forked! PID=%ld Child=%ld\n", getpid(), child);
return 0;
}
在我的机器上,它产生了以下输出:
forked! PID=3694 Child = 0
forked! PID=3696 Child = 0
forked! PID=3693 Child = 1
forked! PID=3695 Child = 1
long f1,f2,f3; (f1 = fork()) && ((f2 = fork()) || (f3 = fork()));
然后打印PID和三个单独的值。
这段代码:
fork();
fork() && fork() || fork();
fork();
自身获得20个进程,而Printf将运行20次。
而对于
fork() && fork() || fork();
printf将总共执行5次。
fork() && fork() || fork();
,而这里的问题使用了fork() && (fork() || fork());
。如此处讨论的那样存在一个合并:“ meta.stackoverflow.com/questions/281729/… ”。您可能需要编辑答案,以通知将来的读者。