C语言 fgets()在到达文件末尾时读取前面的行(使用fork)

slmsl1lt  于 2023-03-01  发布在  其他
关注(0)|答案(1)|浏览(180)

作为用C语言进行多处理器编程的实践,我一直在尝试制作一个可以使用文件作为进程之间通信方式的程序,这部分程序应该使用子进程来读取文件的内容并将其复制到临时文件中,然后将它们从临时文件复制到输出文件中(最好是一行一行地这样做)。问题是,在读完文件的所有行而似乎没有出现任何问题之后,循环只是回到第2行,重新开始,一次又一次,一次又一次...出于某种原因。
当我使用单个进程时,它工作得很好,但这不是我试图实现的目标。其他似乎有帮助的事情是用write()调用替换fprintf()调用(摆脱了在输出文件中一路重复的行)我想认为问题与fgets在我认为应该返回NULL的时候没有返回有关,但我不知道为什么会发生这种情况。我想我从这一点上得到的唯一教训是永远不要在循环内使用fork(),因为这几乎是我的问题和我找到的解决方案没有共同点的一件事,哈哈。下面是我使用的代码的一些细节:
图书馆:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

所讨论的程序(它位于main()中的一些Assert之后):

//opening files with pathnames given as input, creates or overwrites output file
  FILE *Nombres = fopen(argv[1], "r");
  FILE *Apellidos = fopen(argv[2], "r");
  FILE *Output = fopen(argv[3], "w");

  //temp file with a fixed name so i can test around
  char *tempname = "aaa.txt";
  FILE *Tmp = fopen(tempname, "w+");
  char linea[MAXIMA_LONGITUD_LINEA];
  pid_t hijoid;

  while (fgets(linea, MAXIMA_LONGITUD_LINEA, Nombres) != NULL) {
    printf("%s\n", linea);

    Tmp = fopen(tempname, "w+"); //clear tempfile contents
    hijoid = fork();

    if (hijoid == 0) {
      write(fileno(Tmp), linea, strlen(linea));
      exit(0);
    } else {
      waitpid(hijoid, NULL, 0);
      rewind(Tmp);

      if (fgets(linea, MAXIMA_LONGITUD_LINEA, Tmp) != NULL) {
        write(fileno(Output), linea, strlen(linea));
      } else {
        printf("Line couldn't be read.\n");
      }

    }
  }
}
    • 编辑:**这是一个大学作业,旨在测量使用管道和信号与不使用管道和信号之间的时间差,现在看到这种方法没有任何进展,而且无论如何也不应该这样做,我只是继续使用管道,没有出现很多问题。不介意分享代码,但我认为这已经有点超出主题了。
nkhmeac6

nkhmeac61#

其他似乎有帮助的事情是用write()调用替换fprintf()调用(消除了输出文件中重复的行)。
read()write()的典型实现不在用户空间中执行缓冲1,而标准流被缓冲。
第17节第7.21.3节第7页:
当且仅当可以确定标准输入和标准输出流不涉及交互式设备时,该流才被完全缓冲。
C17第5.1.2.3节第7页:
交互式设备的构成由实现定义。
使用fork()时,父代的整个虚拟地址都复制到子代中。如果在调用fork()之前,父代有缓冲的数据,则父代和子代都有相同的缓冲数据。
使用NULL参数调用fflush()将清空所有由C标准(或更高标准)定义行为的流。另一个选项是使用setvbuf()/setbuf()禁用缓冲。
这个程序的目标我不清楚,UNIX中进程间通信的传统方法是pipe(),而不是文件。

脚注:

1

    • 术语 * 无缓冲 * 表示每次读取或写入都会调用内核中的系统调用。**这些无缓冲I/O函数不是ISO C的一部分,而是POSIX. 1和单一UNIX规范的一部分。

相关问题