fork()系统调用的工作(C程序)

Working of fork() system call(C program)

当我 运行 这段代码时,它打印 "hello world" 20 次。根据我的理解,它应该打印 32 次。此外,每个 运行 的换行符打印方式不同。我不明白这一点。请帮忙。

int
main(int argc, char** argv){
    if(fork() || fork())
        fork();
    if(fork() && fork())
        fork();
    printf("\nhello world");
    return 0;
}

要理解你必须剖析这两个结构。首先构造

if( fork() || fork() )
    fork();

或者展开短路的另一种写法或者:

if( !fork() )
    if( !fork() )
        goto not_taken;
fork();
not_taken:

或没有goto

if( !fork() ) {
    if( fork() )
        fork();
}
else
    fork();

进程数将增加五倍。这是因为首先原始进程分叉,然后在子进程中 fork 将 return 归零,它将再次 fork(短路或)。然后,如果这些 returned 中的任何一个非零(即分叉的父进程),它将再次分叉 - 这恰好在父进程中完成,它是子进程。即条件中的 fork 将被调用一次,最后一个 fork 将被调用一次 运行。

现在是第二个构造:

if( fork() && fork() )
    fork();

或展开短路和:

if( fork() )
    if( fork() )
        fork();

进程数将翻四倍。原因是第一个 fork 将是 运行 在父进程中,如果 return 非零(即父进程),第二个 fork 将被调用并且如果 returns 非零,则最后会。所以这里所有三个 fork 都在原始过程中被调用 - 这意味着它被调用了三次。

所以第一个构造将使它们成为五个进程,然后第二个构造将为每个进程再创建三个。这意味着我们将有 5*4 个进程。

你没有获得一致的换行符的原因可能主要是由于 printf 缓冲。 printf 只会立即打印出一个换行符,然后在它终止时写入其余数据,这意味着它们分两步打印字符串。我们有 20 个进程首先打印一个换行符,然后同时打印 "hello world" - 无法保证不同进程打印内容之间的顺序。

一个小的可能性是实际的打印输出不需要是原子的。那是一个进程可能会写入 "hell",然后第二个已经写入 "hello " 的进程开始写入,这可能是 "world" - 这将导致 "hellworld"。

让我们数一数每个fork被调用了多少次。在这个区块中有 3 个分叉:

if(fork() || fork())
    fork();

第一个 fork 被第一个进程调用 1 次。

第二个 fork 仅被调用 1 次,由第二个进程调用。 (第一个过程没有达到)

第 3 个分支被第一个和第二个进程调用 2 次。

所以,此时您已经有 5 个进程。

对于这个区块还有另外 3 个分叉:

if(fork() && fork())
    fork();

第一个 fork 被调用 1x 5 次。这里fork出来的子进程直接去printf

第二个 fork 被调用 1x 5 次。仍然,分叉的子进程转到 printf.

第 3 个 fork 被调用 1x 5 次。

所以你总共 20

如果您分别评估两个 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 个。