为什么简单的C程序输出无法预测地添加/删除换行?

时间:2011-07-27 22:51:33

标签: c gcc cygwin fork

首先,我在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 个答案:

答案 0 :(得分:3)

我觉得这是由冲洗行为引起的。尝试在每个print语句后调用fflush(stdout);,看看是否会改变结果。

有关详细信息,我建议您阅读this question的答案(尤其是this explanation of ISO behavior for buffered and unbuffered streams)。

答案 1 :(得分:0)

Here是驱除困扰你的计算机的恶魔的一种可能的方法:)也就是说,尝试在Cygwin bash shell或Windows的命令提示符上运行该程序。问题是,输出没有在\n上刷新。要刷新它,请在每次fflush(stdout)通话后尝试printf

答案 2 :(得分:0)

这是fork()的正常行为。您的代码导致了非常好的调度程序交互。事实上,这已被用作低质量的RNG。

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

如果添加usleep(500000),您的代码应该按照您的大多数时间执行;到一边的顶部;但是不应该依赖这种行为。

fork()的目的是创建两个独立的进程。有一些标准的处理间锁定机制可以让你的代码工作;然而使用它们几乎总是一个错误。标准的UNIX规则有一个原因:“如果一个程序没有什么可说的,它就应该说什么。”这使得它们可以作为后台进程轻松运行。

顺便说一下,你设置了一些非常类似于我们用来演示调度程序不可预测性的技巧。