2016-03-17 13 views
5

Ich mache ein Programm für die Schule, wo ich ein Multiprocess-Programm habe, wo jeder Prozess einen Teil einer Datei liest und sie zusammenarbeiten, um die Anzahl der Wörter in der Datei zu zählen. Ich habe ein Problem, bei dem, wenn es mehr als 2 Prozesse gibt, alle Prozesse EOF aus der Datei lesen, bevor sie ihren Teil der Datei gelesen haben. Hier ist der relevante Code:EOF erreicht vor Ende der Datei

#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; 
} 

Ausgabe, wenn die Datei mit 3-Prozesse ausgeführt werden:

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. 

Der Test-Datei, die den Fehler verursacht: https://dl.dropboxusercontent.com/u/16835571/test34.txt

Compile mit:

gcc main.c -o wordc-mp 

und laufen als:

wordc-mp test34.txt 3 

Es ist erwähnenswert, dass nur diese bestimmte Datei mir Probleme gibt, aber die Offsets des Fehlers ändern sich ständig, so dass es nicht der Inhalt der Datei ist.

+0

Jonathan Vermutung richtig sein, aber man sollte immer ein [Minimal komplette Nachweisbare Beispiel] Post (http://stackoverflow.com/help/mcve), wenn Sie nach Debugging-Hilfe fragen. – user3386109

+0

Okay, ich werde daran arbeiten, das erledigt zu bekommen –

+0

@ user3386109 Fertig. Der Link befindet sich im Bearbeitungstext. –

Antwort

3

Sie haben Ihren Dateideskriptor vor dem Verzweigen erstellt. Ein untergeordneter Prozess erbt den Dateideskriptor, der auf dieselbe Dateibeschreibung des übergeordneten Elements verweist, und so führt das Vorrücken mit einem der untergeordneten Elemente den Cursor für alle untergeordneten Elemente voran.

Von "Mann fork", können Sie die Bestätigung haben:

  • The child process is created with a single thread—the one that called fork(). The entire virtual address space of the parent is replicated in the child, including the states of mutexes, condition variables, and other pthreads objects; the use of pthread_atfork(3) may be helpful for dealing with problems that this can cause.

  • The child inherits copies of the parent's set of open file descrip‐ tors. Each file descriptor in the child refers to the same open file description (see open(2)) as the corresponding file descriptor in the parent. This means that the two descriptors share open file status flags, current file offset, and signal-driven I/O attributes (see the description of F_SETOWN and F_SETSIG in fcntl(2)).

+0

Ich habe das gemacht, aber wir haben in der Klasse getestet und ich habe mich auch selbst getestet, dass das Vorrücken in entweder dem Kind oder dem Elternteil in keinem der anderen voranschreitet.Außerdem können Sie sehen, in welcher Position sich jeder Prozess in der Datei befand, als es zu EOF kam, und keiner von ihnen ist das tatsächliche Ende der Datei. –

+0

Eigentlich ging voran und versuchte sich zu bewegen, als ich die Datei öffnete und es reparierte. Nicht sicher, warum es im Test in der Klasse funktioniert hat, aber trotzdem, danke für die Antwort! Und tut mir leid, dass ich es anfänglich abgeschrieben habe. –

+1

Wie Sie sehen können, ist dies in der man-Seite von fork dokumentiert. Während der Forking virtueller Speicher erhalten bleibt (eine ganze Kopie wird erstellt), sind Dateideskriptoren mit dem System verbunden und der Dateideskriptor (der ein Zeiger auf eine Dateibeschreibung ist) wird kopiert, verweist aber auf die gleiche Beschreibung (die nicht kopiert wird). –