【问题标题】:a simple fork program一个简单的分叉程序
【发布时间】:2014-04-08 20:53:42
【问题描述】:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main ()
{
  pid_t child_pid;
  printf ("the main program process ID is %d\n", (int) getpid());
  child_pid = fork () ;
  if (child_pid != 0) 
  {
    printf ("this is the parent process, with id %d\n", (int) getpid ());
    printf ("the child's process ID is %d\n",(int) child_pid );
  }
  else
    printf ("this is the child process, with id %d\n", (int) getpid ());
  return 0;
}

我编写了一个简单的 fork 程序来创建一个进程,当我运行该程序时,我得到如下输出:

the main program process ID is 3322
this is the child process , with ID 0

现在我的意思是,为什么 if 块没有像在父进程中那样执行,fork() 的返回值不等于 0 那么为什么我没有得到任何输出if 块?

【问题讨论】:

  • @Ishmeet 这不是 fork 的工作方式。
  • 我刚刚在 Debian 7 和 Mac OSX 19.9 平台上对此进行了测试,它们都完全按照他们应该做的那样做。等待(NULL);在你的父块中只是为了踢。似乎您的父进程 io 在分叉后被重定向或压制。奇怪。
  • 在 Red Hat Enterprise Linux 6 中对其进行了测试。它可以正常工作。你的结果确实很奇怪。您使用什么操作系统/版本和编译器/版本?
  • 你的程序是这样运行的吗:./a.out &gt; out-file?
  • 首先我做了这个gcc -o fork fork.c 然后我做了这个./fork

标签: c unix operating-system fork


【解决方案1】:

下面的代码至少有两个问题:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main ()
{
    pid_t child_pid;
    printf ("the main program process ID is %d\n", (int) getpid());
    child_pid = fork () ;
    if (child_pid > 0) 
    {
        printf ("this is the parent process, with id %d\n", (int) getpid ());
        printf ("the child's process ID is %d\n",(int) child_pid );
    }
    else if (child_pid == 0)
        printf ("this is the child process, with id %d\n", (int) getpid ());
    else
        printf ("fork failed\n");

    return 0;
}
  1. 在第一个 printf() 之后没有刷新输出缓冲区。

    如果这个程序的输出被重定向到一个文件,输出将变成块缓冲,那么这个printf()的输出可能会也可能不会被写入输出文件,因此,输出文件可能是五行或四行(实际上,大多数是五行)。

    在第一个printf() 之后添加fflush(stdout); 可以解决此问题。

  2. 父进程在子进程之前终止。

    在这种情况下,这个程序几千次运行中的一两次,子进程的输出就丢失了,输出文件只有三行。但是在添加fflush() 之后,输出文件应该是四行。

    我真的不明白为什么会发生这种情况,或者它是否正确。但幸运的是,它很容易解决。在第三个printf() 之后添加一个wait(NULL); 就足够了。


这是来自Art的一些非常有用的解释:

  1. POSIX 要求 fork 后子进程中的文件描述符指向相同的文件描述(文件描述与文件描述符不同)。文件描述包含(除其他外)文件偏移量。 printf 最终会通过 write 写出它的输出,并保证 write 原子地更新文件偏移量并写出数据。因此,只要程序不寻找,在分叉程序中重定向输出是安全的(你不应该在 stdout 和 printf 绝对不应该这样做)。

  2. 上一条评论中不包含的引用:file descriptionfork

【讨论】:

  • POSIX 要求 fork 后子进程中的文件描述符指向相同的文件描述(文件描述和文件描述符不是一回事)。文件描述包含(除其他外)文件偏移量。 printf 最终会通过write 写出它的输出,write 保证自动更新文件偏移量并写出数据。因此,只要程序不寻找,在分叉程序中重定向输出是安全的(你不应该在 stdout 上这样做,printf 绝对不应该这样做)。
  • 上一条评论中不符合的引用:file description, fork
  • @Art 如果我将该程序的输出重定向到一个文件,有时该输出文件确实包含少于 5 行的文本,但没有混合行,只有一些整行丢失。您可能想自己测试一下。顺便说一句,您可能需要运行该程序数百次才能重现此现象。
  • 那么你的操作系统中的某些东西坏了。或者更有可能的是,您在第二个进程退出之前计算文件中的行数(因为这里的示例代码没有正确地wait)。我已经运行了数千次并且它的行为正确。如果这是 stdio 中的缓冲问题,它将以一种确定的方式运行,但 stdout 始终是行缓冲的,所以应该没问题。写入同一个文件的两个分叉进程是完美定义的,并且自 unix 出现以来就一直如此。否则从 shell 脚本或 make 重定向输出将不起作用,它总是这样做。
  • @Art 重定向这个程序的输出,至少会暴露这段代码的两个问题: 1.它没有在fork()之前刷新输出缓冲区,所以第一个printf()的内容可能是输出一次或两次; 2. 父进程没有等待子进程退出,这种情况下子进程的输出可能会丢失。虽然我不知道为什么会这样,也不知道这是否正确,但很容易修复,在第三个printf() 之后添加一个wait(NULL); 就足够了。
猜你喜欢
  • 2014-08-15
  • 2014-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-18
  • 2017-09-28
相关资源
最近更新 更多