Fork()创建新进程并为子进程和父进程编写文件

3

我是fork()函数、父子进程的新手,对我编写的代码背后的逻辑有些困惑,并未实现我的期望。以下是我写的代码:

 int main (int argc, char** argv)
 {
     FILE *fp_parent;
     FILE *fp_child;

     fp_parent = fopen ("parent.out","w");
     fp_child = fopen ("child.out","w");

     int test_pid;
     printf ("GET HERE\n");

     fprintf (fp_parent,"Begin\n"); // MY CONCERN

     for (int i = 0; i < 1; i++) //for simplicity, just fork 1 process.
     {                          // but i want to fork more processes later
        test_pid = fork();
        if(test_pid < 0)
        {
          printf ("ERROR fork\n");
          exit (0);
        }
        else if(test_pid == 0) // CHILD
        {
          fprintf(fp_child,"child\n");
          break;
        }
        else //PARENT
        {
          fprintf(fp_parent,"parent\n");
        }
     }
     fclose(fp_parent);
     fclose(fp_child);
 }

因此,上述代码的输出结果为:
 to stdout: GET HERE

 in parent.out:

 Begin

 parent

 Begin

 in child.out:

 child

我的主要问题是我不太明白为什么“Begin”会被写入parent.out两次。如果我完全删除for循环,那么只会写入一个“Begin”,这是预期的。
所以我认为这是由于fork()引起的,肯定是我错过了或不理解其中的一些逻辑。你们能帮我解释一下吗?
我的计划是在for循环之前在parent.out中写入一些内容,并在for循环期间在parent.out中写入一些内容。子进程将写入child.out。
1个回答

4

C语言中,使用FILE结构进行的输入/输出操作在用户进程级别上进行缓冲。在您的情况下,您写入到fp_parent的输出实际上并没有写入磁盘,而是在fork时保留在本地缓冲区中。 fork创建了一个整个进程的副本,包括包含Begin的缓冲区,这就是为什么它会在文件中出现两次的原因。在fork之前尝试放置fflush(fp_parent);。 这将刷新缓冲区,并且脏行将从文件中消失。


fflush可以使用。但是我尝试在fprintf之后插入sync,并获得相同的结果(parent.out中的“Begin”被重复)。为什么这不起作用呢? - Alex Hoppus
请您指定一下,在内核空间中这个缓冲区位于哪里? - Alex Hoppus
1
这与内核无关。使用FILE进行的I/O在标准库中进行缓冲,该库与您的代码链接并生成可执行程序。这意味着它发生在与您自己的代码通过自己的代码进行缓冲时相同的级别上。缓冲区在程序地址空间中由您的程序物理分配,这就是它们被fork复制的原因。如果您不想使用这些缓冲区,请使用没有f的I/O函数,即openwriteclose - Marian
谢谢您的解释,现在我明白了。 - Alex Hoppus
谢谢你,@Marian。这正是我所期望的完美解决方案。你刚刚救了我的一天 :) - LKT

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