fgets() 在它应该到达文件末尾时读取前面的行(使用 fork)

问题描述 投票:0回答:1

作为C多处理器编程的实践,我一直在尝试制作一个可以使用文件作为进程间通信方式的程序。该程序的这一部分应该使用子进程来读取文件的内容并将它们复制到临时文件中,然后将它们从临时文件复制到输出文件中(最好逐行执行此操作)。问题是,在读取文件的所有行后似乎没有出现任何问题,循环只是回到第二行并再次开始,又一次又一次......出于某种原因。

当我使用单个进程时它工作正常,但这不是我想要实现的目标。其他似乎有帮助的事情是用 write() 调用替换 fprintf() 调用(摆脱了输出文件中重复的行)。我想这个问题与 fgets 在我认为应该返回 NULL 时不返回 NULL 有关,但我不知道为什么会发生这种情况。我认为此时我从中得到的唯一教训是永远不要在循环内使用 fork() ,因为这几乎是我的问题和我发现的解决方案没有共同点的一件事,哈哈。以下是我正在使用的代码的一些细节:

图书馆:

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

有问题的程序(在一些断言之后它在 main() 中):

//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");
            }
            
        }
}

提前致谢!

c loops file fork
1个回答
0
投票

其他似乎有帮助的事情是替换 fprintf() 调用 使用 write() 调用(摆脱了沿途重复的行 输出文件)。

read()
write()
的典型实现不在用户空间中进行缓冲1,而标准流是缓冲的。

C17 § 7.21.3p7:

如果标准输入和标准输出流被完全缓冲 并且只有当可以确定流不引用 互动装置。

C17 § 5.1.2.3p7:

交互设备的构成是实现定义的。

使用

fork()
,父项的整个虚拟地址被复制到子项中。如果在调用
fork()
之前,父级有缓冲的数据,则父级和子级都将具有相同的缓冲数据。

使用

fflush()
参数调用
NULL
将清空所有行为由 C 标准(或更多)定义的流。另一种选择是使用
setvbuf()
/
setbuf()
.

禁用缓冲

我不清楚该计划的目标。 UNIX 中进程间通信的常规方式是

pipe()
,而不是文件。请参见UNIX 网络编程:进程间通信。


脚注:

1

术语unbuffered意味着每次读取或写入都会调用一个系统 在内核中调用。 这些无缓冲的 I/O 函数不是 ISO 的一部分 C,但它们是 POSIX.1 和单一 UNIX 规范的一部分。

© www.soinside.com 2019 - 2024. All rights reserved.