什么种族导致输出看起来不同?

What Race Causes the Output to Look Different?

我在去年的期中考试中被问到这个问题。

Consider the following program.

 #include <stdio.h>
 #include <unistd.h>
 int main (void) {
  int pid = getpid ();
  printf ("hello world (pid:%d)\n", pid);
  int rc = fork();
  if (rc < 0) {
   fprintf (stderr, "fork failed\n");
   retrun 1;
  }
  pid = getpid();
  if (rc == 0) {
   printf ("hello, I am child (pid:%d)\n", pid);
  } else {
   printf("hello, I am parent of %d (pid:%d)\n", rc, pid);
  } 
  return 0;
 }

And consider the following behavior that I got when I compiled and ran this program:

$ gcc -02 -Wall question.c
$ ./a.out # First program run
hello world (pid:20600)
hello, I am parent of 20601 (pid:20600)
hello, I am child (pid:20601)
$ ./a.out | cat # Second program run
hello world (pid:20605)
hello, I am parent of 20607 (pid:20605)
hello world (pid:20605)
hello, I am child (pid:20607)

a) What race could cause the output to look substantially different from either the first or the second run, and what would this output look like?

b) Explain each different in the outputs of the two program runs.

对于 (a) 部分,我认为子进程和父进程之间存在竞争,并且子进程可以在父进程之前打印,但显然这是错误的。是否有任何其他种族会导致输出不同?为什么我的回答是错误的?

对于 (b) 部分,我在很多事情上都犹豫不决。首先是我看到 运行 中的 PID 不同,但我对此没有很好的解释。其次,第二个 运行 中的额外 hello world 是因为程序 运行 使用管道和 cat 命令的方式?

问题是您将输出通过管道传输到 cat

默认情况下,当 stdout 连接到终端或控制台时,stdoutline buffered 这意味着内部缓冲区在换行符(或缓冲区已满时,或调用 fflush 时)。

但是当stdout连接到终端或控制台时,就像连接到管道时,它会完全 缓冲。这意味着它只会在缓冲区变满或调用 fflush 时被刷新。打印换行符没有做任何特别的事情,换行符只是添加到缓冲区。

现在,因为 stdout 已完全缓冲,包含第一个 printf 调用内容的缓冲区将作为 fork 调用的一部分复制到子进程,并将子进程退出时刷新。