当我通过管道传输程序的输出时,为什么我的分叉程序的输出会有所不同?

发布于 2024-10-13 14:59:46 字数 758 浏览 7 评论 0原文

我正在查看 fork 上的一些简单代码,并决定自己尝试一下。我编译了它,然后从 Emacs 内部运行它,得到了与在 Bash 中运行它所产生的输出不同的输出。

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

int main() {
  if (fork() != 0) {
    printf("%d: X\n", getpid());
  }

  if (fork() != 0) {
    printf("%d: Y\n", getpid());
  }

  printf("%d: Z\n", getpid());
}

我用 gcc 编译了它,然后从 Emacs 内部运行 a.out,并将其通过管道传输到 catgrep .,并得到了这个。

2055:X
2055:是 2055:Z
2055:X
2058:Z
2057:是 2057:Z
2059: Z

这不对。只从 Bash 运行它,我得到了(这是我所期望的)

2084:X
2084:是 2084:Z
2085:是 2085:Z
2087:Z
2086: Z

编辑 - 错过了一些换行符

发生了什么事?

I was looking at some simple code on fork, and decided to try it out for myself. I compiled and then ran it from inside Emacs, and got a different output to that output produced from running it in Bash.

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

int main() {
  if (fork() != 0) {
    printf("%d: X\n", getpid());
  }

  if (fork() != 0) {
    printf("%d: Y\n", getpid());
  }

  printf("%d: Z\n", getpid());
}

I compiled it with gcc, and then ran a.out from inside Emacs, as well as piping it to cat, and grep ., and got this.

2055: X
2055: Y
2055: Z
2055: X
2058: Z
2057: Y
2057: Z
2059: Z

This isn't right. Running it just from Bash I get (which I expected)

2084: X
2084: Y
2084: Z
2085: Y
2085: Z
2087: Z
2086: Z

edit - missed some newlines

What's going on?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

花开柳相依 2024-10-20 14:59:46

不同进程写入输出的顺序是完全不可预测的。所以唯一令人惊讶的是,有时“X”打印语句有时会出现两次。

我相信这是因为有时在第二个 fork() 处,包含“X”的输出行位于输出缓冲区中,需要刷新。所以这两个进程最终都会打印它。由于 getpid() 已被调用并转换为字符串,因此它们将显示相同的 pid。

我能够重现多个“X”行,但如果我在第二个 fork() 之前添加 fflush(stdout);,我总是只能看到一个“X”行并且始终总共 7 行。

The order in which different processes write their output is entirely unpredictable. So the only surprise is that sometimes the "X" print statement sometimes happens twice.

I believe this is because sometimes at the second fork(), an output line including "X" is in an output buffer, needing to be flushed. So both processes eventually print it. Since getpid() was already called and converted into the string, they'll show the same pid.

I was able to reproduce multiple "X" lines, but if I add fflush(stdout); just before the second fork(), I always only see one "X" line and always a total of 7 lines.

揽清风入怀 2024-10-20 14:59:46

我想我知道发生了什么事。当输出是 tty 和管道或文件时,stdio 缓冲会有所不同。子进程继承父进程的缓冲区。当它们被冲洗时,你可以获得双倍输出。

如果您

fflush(stdout);

在每次 printf() 调用之后添加,您就会明白我的意思。

有趣的是,当标准输出是 tty 设备时,情况有所不同。库可能知道这意味着什么,并在每次换行后刷新,或者类似的事情。

I think I know what's going on. The stdio buffering will be different when output is a tty versus when it's a pipe or a file. The child processes inherit the parent buffers. When they're flushed, you can get double output.

If you add

fflush(stdout);

right after each printf() call, you'll see what I mean.

The interesting thing is that it's different when standard output is a tty device. It may be that the library knows what that means, and flushes after each line break, or something like that.

雨夜星沙 2024-10-20 14:59:46

所以我想您想知道为什么您会得到多个“X”?

这是因为缓冲输出被刷新两次。

当您通过管道传输程序的输出时,stdio 库会识别出您的输出不是终端,并且它会切换到块缓冲而不是行缓冲。因此,当进程分叉时还没有任何输出,因此现在父进程和子进程都有待处理的输出。

So I imagine you are wondering why you are getting more than one "X"?

This is because buffered output is being flushed twice.

When you pipe a program's output, the stdio library recognizes that your output is not a terminal, and it switches to block buffering instead of line buffering. Consequently, there isn't yet any output when the process forks and so now both parent and child have pending output.

日裸衫吸 2024-10-20 14:59:46

如果您在 fork 之前使用过 stdout,则必须fork() 之前调用 fflush(stdout) (对于您使用的任何其他输出FILE也是如此)。如果不这样做,就会导致未定义的行为。您看到的效果来自于 stdout 在连接到终端时是行缓冲,但在连接到管道时完全缓冲 。这不是必需的,但标准 (POSIX) 推荐这样做。

If you have used stdout at all before forking, you must call fflush(stdout) before fork() (and likewise for any other output FILEs you use). Failure to do so results in undefined behavior. The effect you're seeing comes from stdout being line-buffered when it's connected to a terminal, but fully buffered when it's connected to a pipe. This is not required, but recommended by the standards (POSIX).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文