EOF在文件结束前到达

时间:2016-03-17 19:00:25

标签: c linux scanf

我正在为学校制作一个程序,我有一个多进程程序,每个进程读取一个文件的一部分,它们一起工作来计算文件中的单词数。我有一个问题,如果有超过2个进程,那么所有进程在读取文件的部分之前从文件中读取EOF。这是相关的代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char *argv[]) {

    FILE *input_textfile = NULL;
    char input_word[1024];
    int num_processes = 0;
    int proc_num = 0; //The index of this process (used after forking)
    long file_size = -1;

    input_textfile = fopen(argv[1], "r");
    num_processes = atoi(argv[2]);

    //...Normally error checking would go here

    if (num_processes > 1) {

        //...create space for pipes

        for (proc_num = 0; proc_num < num_processes - 1; proc_num++) {

            //...create pipes

            pid_t proc = fork();

            if (proc == -1) {
                fprintf(stderr,"Could not fork process index %d", proc_num);
                perror("");
                return 1;
            } else if (proc == 0) {
                break;
            }

            //...link up the pipes
        }
    }

    //This code taken from http://stackoverflow.com/questions/238603/how-can-i-get-a-files-size-in-c
    //Interestingly, it also fixes a bug we had where the child would start reading at an unpredictable place
    //No idea why, but apparently the offset wasn't guarenteed to start at 0 for some reason
    fseek(input_textfile, 0L, SEEK_END);
    file_size = ftell(input_textfile);
    fseek(input_textfile, proc_num * (1.0 * file_size / num_processes), 0);

    //read all words from the file and add them to the linked list
    if (file_size != 0) {

        //Explaination of this mess of a while loop:
        //  if we're a child process (proc_num < num_processes - 1), then loop until we make it to where the next
        //  process would start (the ftell part)
        //  if we're the parent (proc_num == num_processes - 1), loop until we reach the end of the file
        while ((proc_num < num_processes - 1 && ftell(input_textfile) < (proc_num + 1) * (1.0 * file_size / num_processes))
                || (proc_num == num_processes - 1 && ftell(input_textfile) < file_size)){
            int res = fscanf(input_textfile, "%s", input_word);

            if (res == 1) {
                //count the word
            } else if (res == EOF && errno != 0) {
                perror("Error reading file: ");
                exit(1);
            } else if (res == EOF && ftell(input_textfile) < file_size) {
                printf("Process %d found unexpected EOF at %ld.\n", proc_num, ftell(input_textfile));
                exit(1);
            } else if (res == EOF && feof(input_textfile)){
                continue;
            } else {
                printf("Scanf returned unexpected value: %d\n", res);
                exit(1);
            }
        }
    }

    //don't get here anyway, so no point in closing files and whatnot

    return 0;
}

使用3个进程运行文件时的输出:

All files opened successfully
Process 2 found unexpected EOF at 1323008.
Process 1 found unexpected EOF at 823849.
Process 0 found unexpected EOF at 331776.

导致错误的测试文件:isin

编译:

gcc main.c -o wordc-mp

并以:

运行
wordc-mp test34.txt 3

值得注意的是,只有那个特定的文件会给我带来问题,但错误的偏移量会不断变化,因此它不是文件的内容。

1 个答案:

答案 0 :(得分:3)

您在分叉之前已经创建了文件描述符。子进程继承文件描述符,它指向父对象的文件描述,因此,与其中一个子进行前进会使所有子进程前进。

从&#34; man fork&#34;,您可以得到确认:

  
      
  • 子进程是使用单个线程创建的 - 一个   那         叫fork()。父级的整个虚拟地址空间是         复制在孩子身上,包括互斥状态,状况         变量和其他pthreads对象;使用pthread_atfork(3)         可能有助于解决这可能导致的问题。

  •   
  • 孩子继承了父母的一组开放文件描述 -         职权范围。子中的每个文件描述符都指向相同的open         文件描述(参见open(2))作为相应的文件描述符         在父母。这意味着两个描述符共享打开文件         状态标志,当前文件偏移和信号驱动的I / O属性         (参见fcntl(2)中F_SETOWN和F_SETSIG的描述)。

  •