【问题标题】:Need to know how fork works?需要知道 fork 是如何工作的吗?
【发布时间】:2011-08-26 01:55:46
【问题描述】:

我正在尝试以下 C 代码:

int main()
{
    printf("text1\n");
    fork();
    printf("text2\n");
    return 0;
}

我希望得到两个“text1”和两个“text2”的输出,例如:

text1
text1
text2
text2

但是,相反,我得到了:

text1
text2
text2

只有一个“text1”??? 好的,如果子进程从 fork() 执行,那么为什么我会得到两个“text1”:

int main()  
{  
    printf("text1");  
    fork();  
    printf("text2\n");  
    return 0;  
}  

现在的输出是:

text1text2  
text1text2 

如果子进程在fork之后启动,输出应该是:

text1  
text2  
text2  

【问题讨论】:

  • 为什么会期望有两个“text1”副本?在您点击fork之前只有一个进程。
  • @user749391:代码按预期工作。在您真正解释为什么您希望看到两个“text1”之前,无法有意义地回答像您这样的问题。
  • 检查this。它输出为 text1
    text2
    text1
    text2。为什么会有这样的差异

标签: c process fork


【解决方案1】:

fork() 通过将当前进程中的所有内容复制到新进程中来创建一个新进程。这通常包括内存中的所有内容以及 CPU 寄存器的当前值以及一些小的调整。因此,实际上,新进程也会获得进程指令指针的副本,因此它会在原始进程将继续的同一点恢复(fork() 之后的指令)。


为了解决您的更新,printf() 被缓冲。通常,缓冲区在最后遇到换行符'\n' 时会被刷新。但是,由于您省略了这一点,缓冲区的内容会保留并且不会被刷新。最后,两个进程(原始进程和子进程)都将拥有带有"text1" 的输出缓冲区。当它最终被刷新时,您会在两个进程中看到这一点。

在实践中,您应该始终在分叉之前刷新文件和所有缓冲区(包括 stdout),以确保不会发生这种情况。

printf("text1");
fflush(stdout);
fork();

输出应如下所示(按某种顺序):

文本1文本2 文本2

【讨论】:

  • 但是为什么我得到两个“text1”以供关注: int main() { printf("text1");叉(); printf("text2\n");返回0;现在的输出是:text1text2 text1text2 如果子进程在fork之后启动,输出应该是:text1 text2 text2
  • 多么好的解释。哇。谢谢。
【解决方案2】:

分叉的进程获得了变量内存的副本,并且在分叉的时候输出缓冲区还没有被刷新。分叉时没有输出写入控制台,只是缓冲了。因此,两个进程都继续使用缓冲区中已经存在的 text1,因此都打印它。

【讨论】:

  • @adi,要获得预期的输出,您应该在第一个 printf 之后加上 fflush(stdout)
【解决方案3】:

fork 克隆当前进程。新进程将在fork 调用处“开始”,而不是在您似乎期望的main 开始处。因此,当您第一次打印时有 1 个进程,然后当您 fork 时有两个。

由于您在打印"text1" 之后是forking,所以它只打印一次。

在第二个示例中,重复输出是由于输出缓冲造成的 - printf 实际上不会在屏幕上输出任何内容,直到它被刷新或遇到换行符 ('\n')。

因此,第一次调用 printf 实际上只是将数据写入某个缓冲区,然后将数据复制到第二个进程的地址空间,然后第二次调用 printf 将刷新缓冲区,完成"text1" 在两个缓冲区中。

【讨论】:

    【解决方案4】:

    这是因为forked 进程在fork 之后开始,而不是从一开始。 exec 从入口点启动进程并打印您期望的内容。

    【讨论】:

    • 我仍然无法得到它,因为当我从第一个 printf() 中删除 "\n" 时,我也得到了两次 "text1",即 int main() { printf("text1") ;叉(); printf("text2\n");返回0;输出是: text1text2 text1text2
    • 我猜在这种情况下,原始进程和分叉进程都使用“text1”继承缓冲输出,因为行尾没有导致缓冲区刷新。我假设如果您在分叉之前对标准输出进行刷新,您会看到您期望看到的内容。
    【解决方案5】:

    子进程将从 fork() 的位置开始,所以你得到了正确的输出。

    【讨论】:

    • 正如你所说,子进程将从 fork() 开始,我应该得到 text1text2 text2,在第二种情况下
    【解决方案6】:

    问题 1:输出为
          文本1
          文本2
          文本2

    这是因为 fork() 创建了父进程的精确副本(子进程),并且两个进程在系统调用 fork() 之后立即开始执行。

    问题 2:输出为
          文本1文本2
          text1text2 

    这都是关于缓冲的。请参阅此链接并了解 fork() 基础知识。 http://www.csl.mtu.edu/cs4411.ck/www/NOTES/process/fork/create.html

    【讨论】:

      【解决方案7】:

      来自man 2 fork:fork 向子进程返回0。

      value = fork();
      if( value == -1 ) {
        printf( "fork failed\n" );
        exit(1);
      }
      if( value ) {
        printf( "test1\n" );
      } else {
        printf( "test2\n" };
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多