首页 > 解决方案 > 什么种族导致输出看起来不同?

问题描述

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

考虑以下程序。

 #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;
 }

并考虑我在编译和运行这个程序时得到的以下行为:

$ 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) 什么比赛会导致输出看起来与第一次或第二次运行有很大不同,这个输出会是什么样子?

b) 解释两个程序运行的输出中的每个不同。

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

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

标签: cpipeforkchild-process

解决方案


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

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

但是当stdout没有连接到终端或控制台时,比如当它连接到管道时,它就会完全缓冲。fflush这意味着只有在缓冲区满或被调用时才会刷新它。打印换行符并没有什么特别的作用,换行符只是添加到缓冲区中。

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


推荐阅读