【问题标题】:fork() causes the beginning of the parent's main to execute if shell output is piped somewhere [duplicate]如果 shell 输出通过管道传输到某处 [重复]
【发布时间】:2019-07-21 17:37:38
【问题描述】:

我试图使用fork() 函数,但出现了一些奇怪的行为。父进程的主要功能的一部分(不是全部)似乎在调用fork() 之后立即运行,但前提是可执行文件的输出通过管道传输到命令行的某处。

我在 Mac OS Mojave 上注意到了这一点,但我在 Ubuntu 18.04 上测试了相同的代码,它表现出相同的行为。我不知道为什么会这样。

这是fork.c文件中的测试代码:

#include <stdio.h>
#include <unistd.h>

int main(void)
{
        pid_t child_pid;
        printf("Beginning of main for process %d\n", getpid());
        if ((child_pid = fork())) {
                printf("Forked process %d\n", child_pid);
        } else {
                printf("Beginning of forked process %d\n", getpid());
        }
}

这是一个使用此代码的 shell 会话:

 $ cc fork.c
 $ ./a.out
Beginning of main for process 98373
Forked process 98374
Beginning of forked process 98374
 $ ./a.out | cat
Beginning of main for process 98378
Forked process 98380
Beginning of main for process 98378
Beginning of forked process 98380

如你所见,main() 开头的语句在父进程中执行两次,如果输出通过管道传送到某处。

【问题讨论】:

  • stdout 通常是行缓冲的,但如果连接到管道则完全缓冲。在fork 之前调用fflush(NULL),它会按您的预期工作。

标签: c unix fork


【解决方案1】:

这与 I/O 缓冲有关。

默认情况下,控制台是行缓冲的,因此如果您的输出字符串以换行符结尾并且您不重定向,则输出会立即刷新。但是当您重定向标准输出时,换行符不会刷新缓冲区。因此,当您 fork 父子节点在输出缓冲区中都有一行文本时,两者都会打印第一行。

您可以通过使用fflush 显式刷新缓冲区来解决此问题。

printf("Beginning of main for process %d\n", getpid());
flush(stdout);

【讨论】:

    猜你喜欢
    • 2017-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    • 2015-08-19
    • 1970-01-01
    相关资源
    最近更新 更多