为什么简单的C程序输出时会不可预测地添加/删除换行符?

3

首先,我在Windows 7系统上使用cygwin版本1.7.1。代码是使用gcc编译并从bash提示符中运行的。接下来进入正题:

我正在研究fork()和exec()的工作原理,因此我查看了维基百科。在那里,我找到了以下简单的C代码,用于进行一些fork-on-fork操作:

#include <stdio.h>   /* printf, stderr, fprintf */
#include <unistd.h>  /* _exit, fork */
#include <stdlib.h>  /* exit */
#include <errno.h>   /* errno */

int main(void)
{
   pid_t  pid;

   /* Output from both the child and the parent process
    * will be written to the standard output,
    * as they both run at the same time.
    */

   pid = fork();
   if (pid == -1)
   {
      fprintf(stderr, "can't fork, error %d\n", errno);
      exit(EXIT_FAILURE);
   }

   if (pid == 0)
   {
      /* Child process:
       * When fork() returns 0, we are in
       * the child process.
       * Here we count up to ten, one each second.
       */
      int j = 0;
      for (j = 0; j < 10; j++)
      {
         printf("child: %d\n", j);
         sleep(1);
      }
      _exit(0);  /* Note that we do not use exit() */
   }
   else
   {
      /* Parent process:
       * When fork() returns a positive number, we are in the parent process
       * (the fork return value is the PID of the newly created child process).
       * Again we count up to ten.
       */

      int i = 0;
      for (i = 0; i < 10; i++)
      {
         printf("parent: %d\n", i);
         sleep(1);
      }
      exit(0);
   }
}

现在当我多次编译和运行它时,似乎会出现不可预测的行为...有时会按预期运行,有时会在stdout中包含额外的换行符,有时会省略换行符。以下是输出的示例:

user@HAL10000 ~/c++/sandbox/src
$ gcc fork_and_stuff.c -o fork_and_stuff

user@HAL10000 ~/c++/sandbox/src
$ ./fork_and_stuff.exe
parent: 0child: 0
parent: 1child: 1
parent: 2child: 2

parent: 3child: 3
parent: 4child: 4
parent: 5child: 5

child: 6
parent: 6
child: 7
parent: 7
child: 8
parent: 8
child: 9
parent: 9

user@HAL10000 ~/c++/sandbox/src
$ ./fork_and_stuff.exe
parent: 0
child: 0
parent: 1
child: 1
parent: 2
child: 2
parent: 3
child: 3
parent: 4
child: 4
parent: 5
child: 5
parent: 6
child: 6
parent: 7
child: 7
parent: 8
child: 8
parent: 9
child: 9

user@HAL10000 ~/c++/sandbox/src
$ ./fork_and_stuff.exe
parent: 0child: 0

parent: 1child: 1

parent: 2child: 2

parent: 3child: 3

parent: 4child: 4

child: 5
parent: 5
parent: 6child: 6

parent: 7child: 7

child: 8parent: 8

parent: 9child: 9

这是一些看起来很可怕的输出。我的电脑被鬼附了吗?如果是,是什么东西附在上面了?我该如何驱除它?

3个回答

3

请参考 POSIX 中的 2.5.1:http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_05_01 - R.. GitHub STOP HELPING ICE
因此,在打印语句之后添加 fflush(stdout); 并没有改变行为... 即使字符串有一个换行符并且我礼貌地要求它刷新。 - Jimmy

0

这里有一种可能的方法来驱除困扰你电脑的邪恶精灵 :) 也就是说,尝试在Cygwin bash shell或Windows命令提示符上运行程序。问题是,输出没有在\n后被刷新。为了刷新它,请在每个printf调用之后尝试fflush(stdout)


我相信我正在Windows命令提示符窗口上运行cygwin bash shell(尽管我已经将其全部设置为超级大,使用旧式光栅字体,白色文本在浅灰色背景上,这让我非常开心)。无论如何,当我输入“echo $TERM”时,它会显示“cygwin”。+1,如果您链接到一篇文章,该文章还使用“haunt”一词。 - Jimmy

0

这是fork()的正常行为。你的代码导致了一个非常好的调度交互。实际上,这已经被用作低质量的随机数生成器。

调用fflush()可能会降低概率,但实际上并不能消除它发生的可能性。

如果在一侧的顶部添加usleep(500000);,你的代码应该大部分时间都能做到你想要的,但是不应该依赖这种行为。

fork()的目的是创建两个独立的进程。有标准的进程间锁定机制可用于允许你的代码工作;然而,使用它们几乎总是错误的。有一个UNIX标准规则:“如果程序没有什么惊人的话要说,那就什么也不要说。”这使得它们可以轻松地作为后台进程运行。

顺便说一下,你设置了类似于我们用来展示调度器不可预测性的技巧。


我担心你可能是正确的;fflush()似乎没有任何效果。这并不一定有助于我对fork()的理解,因为以前我从来没有遇到过这个设置的输入/输出问题......另外,我想知道它是否只是一个刷新问题,因为如果你看一下程序给出的第一个输出,实际上换行符被丢失了而不仅仅是延迟(即按我的计算,只有16个换行符,而不是预期的20个)。 - Jimmy
您在调用_exit()之前没有调用fflush()。这样做可能会丢失一些输出。 - Joshua

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接