【问题标题】:Omitting or leaving "\n" prints "Hello world" twice in using fork() [duplicate]在使用 fork() 时省略或离开“\n”两次打印“Hello world”[重复]
【发布时间】:2014-06-04 10:31:29
【问题描述】:

我在 linux 上使用 gcc 编译器。

当我运行这段代码时(在 printf 中的 hello world 之后,Notice"\n" 不存在)

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
    printf("Hello world");
    fork();
}

我得到这个输出:Hello worldHello world

另一方面 当我运行这段代码时(注意“\n”出现在 printf 中的 hello world 之后)

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
    printf("Hello world\n");
    fork();
}

我得到这个输出:Hello world

有人可以详细描述一下,为什么省略或留下“\n”会打印两次“Hello world”?

【问题讨论】:

    标签: c process fork


    【解决方案1】:

    我会说这两个版本都不正确。当调用exit() 时,C 运行时将注册atexit 处理程序以刷新标准缓冲区。使程序只打印一次的正确方法是在子进程中调用_exit(0);。这样你的孩子就不会打电话给atexit(这反过来不会刷新缓冲区两次)

    if (fork() == 0)
        _exit(0);
    

    【讨论】:

      【解决方案2】:

      为了详细说明链接问题中的答案并将其与您的问题相关联,stdout 通常会缓冲输入,直到它看到\n,或者您明确地fflush 它。

      当您有\n 时,您将使其在fork() 之前刷新。 如果没有\n,它会 fork 之后刷新,因此它会同时存在于两个进程中。

      在链接的问题中,他们谈论了fflush(),但\n 具有相同的效果,导致stdout 刷新。

      下面的程序也只会看到一张打印:

      #include<stdio.h>
      #include<unistd.h>
      #include<sys/types.h>
      
      int main()
      {
          printf("Hello world");
          fflush(stdout);
          fork();
      }
      

      编辑:由于 Dabo 的评论,\n 只有在 stdout 处于行缓冲模式而不是完全缓冲模式时才会导致刷新。我们可以在下面的程序中观察到,当使用setvbuf 打开完全缓冲模式时,即使使用\n,我们仍然可以看到字符串打印了两次。

      #include<stdio.h>
      #include<unistd.h>
      #include<sys/types.h>
      int main()
      {
          setvbuf(stdout, NULL,_IOFBF, BUFSIZ);
          printf("Hello world\n");
          fork();
      }
      

      输出:

      Hello world
      Hello world
      

      【讨论】:

      • 链接问题的第一个答案的最后一段解释了为什么\n 会改变行为。
      • @Barmar,哎呀,我读得还不够远。我应该删除这个答案还是把它留给其他决定用谷歌搜索\n 并分叉的人?
      • 别说了,对强化概念很有帮助
      • @Dabo,谢谢。我已经用你的笔记更新了答案。
      • @merlin2011 +1,但我仍然决定添加我的答案:)
      【解决方案3】:

      没有\n 意味着“hello world”仍在记忆中 - 准备好愉快地前往终端。

      fork 将复制此内存 - 即现在您有两个进程在内存中具有相同的“hello world”。当程序终止时,它会将其刷新到标准输出。 IE。获得两次。

      但是,如果您将 \n 放入 - 它会立即刷新到标准输出。因此,在调用 fork 之前,此缓冲区将为空。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-23
        • 2012-10-10
        • 1970-01-01
        • 1970-01-01
        • 2012-10-06
        • 2020-02-03
        • 2012-05-28
        • 2017-09-29
        相关资源
        最近更新 更多