【问题标题】:Having child processes printf to redirected stdout correctly让子进程 printf 正确重定向标准输出
【发布时间】:2020-09-09 13:51:57
【问题描述】:

我正在使用freopen()stdout 重定向到一个进程上,只要它只是一个进程,一切都很好。

但是,如果我这样做:

freopen("stdout.txt", "a+", stdout);
printf("Initial line.\n");

int i=0;
while(i<1000)
    {
        if(fork())
            wait(NULL);
        else
            printf("Line %d.\n", i);
        i++;
    }

第一个打印的行会一遍又一遍地重新打印在文件上。我应该做些什么来避免这种情况发生?

【问题讨论】:

  • 您真的要创建数千个进程吗?想想fork 的位置以及子进程每次迭代中发生的情况。
  • The first printed lines are re-printed on the file over and over 这是什么意思?它是如何“重印”的?可以举个例子吗?
  • @Someprogrammerdude 是的
  • @KamilCuk fork() 的子代也包含其他所有内容,例如 stdout,因为子代大多是父代的 1:1 副本。我认为你混淆了fork()exec()
  • 此代码将创建 2**1000-1 个孩子,您确定要这样做吗?也许您在孩子身上忘记了exit()

标签: c fork stdout child-process freopen


【解决方案1】:

第一个打印的行在文件上一遍又一遍地重新打印。

这是因为标准 C 库在使用stdio 函数时将缓冲 应用于标准输出流。特别是,当stdout 被重定向到文件时,缓冲模式从行缓冲变为完全缓冲(缓冲区大小由库定义)。在行缓冲模式下,只有在遇到换行符时才会刷新缓冲区(以及实际写入的数据),在完全缓冲模式下,这只会在达到最大缓冲区大小时发生。

当您创建多个进程时,它们都共享父级的同一个缓冲区。由于在生成新子代之前您没有到达缓冲区的末尾,并且您没有清空它,因此它们都将具有相同的缓冲区内容。之后,当每个孩子死亡时,标准库会自动刷新缓冲区。

我应该做些什么来避免这种情况发生吗?

是的。在创建子级之前刷新缓冲区。

freopen("stdout.txt", "a+", stdout);
printf("Initial line.\n");
fflush(stdout);

// ...

您可能还想在孩子完成工作后的下一个周期之前exit()

int i=0;
while(i<1000)
{
    if(fork()) {
        wait(NULL);
    } else {
        printf("Line %d.\n", i);
        exit(0);
    }

    i++;
}

【讨论】:

  • 在每个fork 之前?还是只有一次?
  • @Jim 是的,基本上在每个fork() 之前。如果你想在任何printf() 之后分叉,你必须确保先fflush()
  • 非常感谢您的回答,但我意识到我正在做其他事情。我没有退出子进程,并且计数器仅在子进程中递增,因此无论如何输出都被搞砸了。如果您愿意,请编辑您的代码以考虑到这一点,以便我接受您的回答!
  • @Jim 好吧...我不知道,但可以肯定,完成了。
猜你喜欢
  • 2013-06-02
  • 2022-12-14
  • 2023-04-05
  • 2011-01-10
  • 1970-01-01
  • 1970-01-01
  • 2016-02-29
  • 2013-07-16
  • 1970-01-01
相关资源
最近更新 更多