是否有任何公式可以知道fork()如何制作当前流程的近乎完美的副本?

时间:2014-02-18 15:58:05

标签: c fork

#include <stdio.h>
main()
{    
    int i, n=1; 

    for(i=0;i<n;i++) { 
        fork();
        printf("Hello!");
    }
}

如果我把n = 1,我很困惑,它打印Hello 2次。

  • 如果n = 2,则打印Hello 8次
  • 如果n = 3,则打印Hello 24次..
  • 依旧......

5 个答案:

答案 0 :(得分:1)

fork()总是能够完美呈现当前流程 - 唯一的区别就是流程ID。

实际上在大多数现代操作系统中,在fork()之后,两个进程共享完全相同的内存块。操作系统仅在新进程写入该内存时才会生成新副本(在称为“写时复制”的操作模式下) - 如果两个进程都没有更改内存,那么它们可以继续共享该内存块,节省整体系统内存。

但作为一名程序员,所有这一切对你来说都是隐藏的。从概念上讲,你可以把它想象成一个完美的副本。

该副本包含fork()发生时的所有变量值。因此,如果fork()for()循环内发生i==2,那么新进程将在for()循环的中途进行,i==2

但是,这些流程不会分享 i。当一个流程在i之后更改fork()的值时,其他流程的i不会受到影响。

要了解程序的结果,请修改程序,以便了解哪条进程正在打印每一行,以及它所处的迭代次数。

#include <stdio.h>
# include <sys/types.h>

main() {
    int i , n=4;
    for(i=0;i<n;i++); {
        int pid = getpid();
        if(fork() == 0) {
            printf("New process forked from %d with i=%d and pid=%d", pid, i, getpid());
        }
        printf("Hello number %d from pid %d\n", i, getpid());
    }
}

由于时间会有所不同,你会得到不同顺序的输出,但是你应该能够理解所有“Hellos”的来源,以及为什么有多少。

答案 1 :(得分:1)

没有单一的“公式”如何完成,因为不同的操作系统以不同的方式完成它。但是fork()做的是它复制了这个过程。通常涉及的粗略步骤:

  • 停止当前流程。
  • 制作新流程,并初始化或复制相关内部结构。
  • 复制进程内存。
  • 复制资源,例如打开文件描述符等。
  • 复制CPU / FPU寄存器。
  • 恢复这两个过程。

答案 2 :(得分:1)

你不只是分叉'主'过程,你也分叉孩子们! 第一次迭代:

m -> c1
//then
m -> c2   c1-> c1.1
m -> c3   c1-> c1.1  c2->c2.1  c1.1 -> c1.1.1

表示i = ....

以这种方式写下来:

main
fork
         child(1)
fork                  child(2)
         fork                     child(1.1)
fork                                          child(3)
         fork                                             child(1.2)
                      fork                                             child(2.1)

依旧......

答案 3 :(得分:0)

当你fork()时,你创建一个新的子进程,它有不同的虚拟内存,但最初显示在与父亲相同的物理内存中。此时,两个进程只能从内存中读取数据。如果他们想要在该公共内存中编写或更改任何内容,则他们使用不同的物理内存并对该内存具有写入属性。因此,当你fork()时,你的孩子最初具有与其父亲相同的i值,但该值对于每个孩子都是单独改变的。

答案 4 :(得分:0)

是的,有一个公式:

fork() 只生成一个几乎相同的流程副本。然而,它返回两次。一旦进入原始进程(父进程,返回子进程pid)和进入子进程一次(返回0)。