2016-03-17 17 views
5

Sto realizzando un programma per la scuola in cui ho un programma multiprocesso in cui ogni processo legge una parte di un file e lavorano insieme per contare il numero di parole nel file. Sto avendo un problema dove se ci sono più di 2 processi, quindi tutti i processi leggono EOF dal file prima che abbiano letto la loro parte del file. Ecco il codice rilevante:EOF raggiunto prima della fine del file

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

uscita quando si esegue il file con 3 processi:

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. 

Il file di prova che causa l'errore: https://dl.dropboxusercontent.com/u/16835571/test34.txt

Compilare con:

gcc main.c -o wordc-mp 

ed eseguire come:

wordc-mp test34.txt 3 

Vale la pena notare che solo quel particolare file mi dà problemi, ma gli scostamenti dell'errore continuano a cambiare, quindi non è il contenuto del file.

+0

ipotesi di Jonathan può essere corretto, ma si dovrebbe sempre postare un [Minimo completa verificabile Esempio] (http://stackoverflow.com/help/mcve) quando si richiede l'aiuto per il debug. – user3386109

+0

Va bene, lavorerò per ottenere quello fatto –

+0

@ user3386109 Fatto. Il link è nel testo di modifica. –

risposta

3

È stato creato il descrittore di file prima della foratura. Un processo figlio eredita il descrittore di file che punta alla stessa descrizione del file del genitore e, quindi, avanzando con uno dei bambini fa avanzare il cursore per tutti i bambini.

Da "uomo forchetta", si può avere la conferma:

  • 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

L'ho fatto, ma ci siamo testati in classe e ho anche provato a me stesso che avanzare sia nel bambino che nel genitore non progredisce in nessuno degli altri.Inoltre, è possibile vedere in quale posizione si trovava ogni processo nel file quando è arrivato a EOF e nessuno di essi rappresenta la fine effettiva del file. –

+0

In realtà è andato avanti e ho provato a spostarmi quando ho aperto il file e l'ho risolto. Non so perché abbia funzionato nel test in classe, ma comunque, grazie per la risposta! E mi dispiace per averlo scritto inizialmente. –

+1

Come potete vedere, questo è documentato nella pagina man di fork. Mentre fora preservare la memoria virtuale (viene eseguita un'intera copia), i descrittori dei file sono correlati al sistema e il descrittore del file (che è un puntatore a una descrizione del file) viene copiato ma si riferisce alla stessa descrizione (che non è copiata). –

Problemi correlati