当我运行此代码时,它会打印“hello world”20次。根据我的理解,它应该打印32次。此外,每次运行时换行符的打印方式也不同。我不明白这一点。请帮忙。
int
main(int argc, char** argv){
if(fork() || fork())
fork();
if(fork() && fork())
fork();
printf("\nhello world");
return 0;
}
答案 0 :(得分:4)
要理解你必须同意这两种结构。首先是构造
if( fork() || fork() )
fork();
或通过展开短路或其他方式书写:
if( !fork() )
if( !fork() )
goto not_taken;
fork();
not_taken:
或没有goto
的
if( !fork() ) {
if( fork() )
fork();
}
else
fork();
将是进程数量的五倍。这是因为首先原始进程分叉,然后作为fork
的子进程将返回零,它将再次fork
(短路或)。然后,如果其中任何一个返回非零(即fork的父级),它将再次fork - 这恰好在父进程中完成,并且它是子进程。也就是说,条件中的fork
将被调用一次,最后fork
将被调用一次。
现在是第二个结构:
if( fork() && fork() )
fork();
或展开短路并且:
if( fork() )
if( fork() )
fork();
过程计数将是四倍。原因是第一个fork
将在父进程中运行,如果返回非零(即父进程),则将调用第二个fork
,如果返回非零,则返回非零将。所以这里所有三个fork
都在原始进程中被调用 - 这意味着它被调用了三次。
因此,第一个构造将使它们成为五个进程,第二个构建将为每个进程创建三个进程。这意味着我们将拥有5*4
个进程。
您没有获得一致换行符的原因可能主要是printf
缓冲。 printf
只会立即打印出换行符,然后在终止时写入剩余的数据,这意味着它们分两步打印字符串。我们有20个进程首先打印换行符然后同时打印“hello world” - 不能保证不同进程打印的顺序。
一个小的可能性是实际的打印输出不需要是原子的。这是一个过程可能会写“地狱”,然后第二个已经写成“你好”的东西可以写成“世界” - 这将导致“地狱世界”。
答案 1 :(得分:0)
让我们计算每个fork调用的次数。在这个区块中有3个叉子:
if(fork() || fork())
fork();
第一个分支在第一个过程中被称为1
时间。
第二个进程只调用第二个分叉1
次。 (第一个过程没有达到它)
第3个分支在第一个和第二个过程中被称为2
次。
所以,此时你已经有 5 个过程。
对于这个区块,还有另外3个分叉:
if(fork() && fork())
fork();
第一个叉子称为1
x 5 次。在这里,分叉的子进程直接转到printf
。
第二叉称为1
x 5 次。仍然,分叉子进程转到printf
。
第3个分支称为1
x 5 次。
所以你总共20
。
答案 2 :(得分:0)
如果分别评估两个if结构,这会容易得多。计算在第一个中创建的进程数,并将其乘以在第二个中创建的数。结果是进程总数和调用printf调用的次数。
(我们假设fork调用不会失败。)
第一个if语句由这个方便的图表显示,其中列是分叉,行是进程。
叉子 - f1,f2,f3
进程 - c0,c1,...,c4
xN - 标记过程的创建,其中N是创建的过程的索引
。 - 标记流程创建
_ - 过程存在且不执行任何操作
(没有字符表示此时不存在该过程)
f1 f2 f3
c0 _ x1 _ x2 _
c1 . x3 x4 _
c2 . _
c3 . _ _
c4 . _
此时存在5个进程,另外创建了4个进程。下一个图表显示了第二个if语句,但仅适用于一个进程:
f1 f2 f3
c0 _ x1 x2 x3 _
c1 . _ _ _
c2 . _ _
c3 . _
这个if语句创建了3个额外的进程,因此存在4个进程。但请记住,我们之前有5个流程,而不仅仅是一个。因此,两个if语句一起创建5 x 4个进程,总共20个。