【问题标题】:What Race Causes the Output to Look Different?什么种族导致输出看起来不同?
【发布时间】:2019-12-05 07:11:22
【问题描述】:

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

考虑以下程序。

 #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 命令运行的方式?

【问题讨论】:

  • 请记住,fork 创建了父进程的完全相同的副本,包括stdout 使用的缓冲区(这是printf 写入的位置)。在第二种情况下,似乎第一个 printf 调用的缓冲区在进程分叉时没有被刷新。
  • @Someprogrammerdude,我很好奇:stdout 不应该被第一个printf 处的\ncharacter 刷新?
  • @GuillaumePetitjean 谢谢,这为我指明了正确的方向! :)
  • 作为旁注,考虑到英语很差,我希望它们不是真正的考试题...
  • @GuillaumePetitjean 是 :) 操作系统课程

标签: c pipe fork child-process


【解决方案1】:

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

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

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

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2015-03-25
  • 1970-01-01
  • 1970-01-01
  • 2021-06-06
  • 2012-02-24
  • 1970-01-01
  • 2022-07-26
  • 2014-08-15
相关资源
最近更新 更多