2016-03-30 8 views
0

ich diesen Code getan habe:Fehler von syncronism in Daten aus einer Datei sendet ein Rohr mit

#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/wait.h> 
#define BUFFER_SIZE 255 
#define PATH "./test.txt" 

int main(int argc, char **argv) 
{ 
    char read_msg[BUFFER_SIZE]; 
    FILE *fp; 
    char buffer[BUFFER_SIZE]; 
    fp = fopen(PATH, "r"); 
    int fd[2]; 
    pid_t pid; 
    if(pipe(fd) == -1){ 
     perror("Pipe failed"); 
     return 1; 
    } 

    pid=fork(); 
    if (pid==-1) 
    { 
     perror("Fork failed"); 
     return 1; 
    } 

    if (pid>0) 
    { 
     close(fd[0]); 
     fgets(buffer, BUFFER_SIZE, (FILE*)fp); 
     do{ 
      write(fd[1],buffer,strlen(buffer)+1); 
      //sleep(1); 
     }while(fgets(buffer, BUFFER_SIZE, (FILE*)fp) != NULL); 
    close(fd[1]); 
    wait(NULL); 
}else{ 
    close(fd[1]); 
    while(read(fd[0], read_msg, BUFFER_SIZE) != 0){ 
    printf("Child had read: %s", read_msg); 
    } 
    close(fd[0]); 
    } 
    return 0; 
} 

Dieser Code muss ein Rohr zwischen dem Vater Prozess und dem Kind-Prozess erstellen. Der Vaterprozess muss die Datei lesen und jede Zeile an den untergeordneten Prozess senden. Der Kindprozess druckt die empfangenen Zeilen.

Aber dieser Code hat einen Fehler. Wenn ich so laufe, bekomme ich nur einige Zeilen des Textes in der Datei. Wenn ich mit dem kommentierten sleep (1) laufe bekomme ich alle Zeilen des Textes.

Kann jemand den Fehler sehen?

Antwort

2

Sie haben zwei Probleme.

hier:

write(fd[1],buffer,strlen(buffer)+1); 

Sie das abschließende Null in die Datei zu schreiben. Wenn Sie read() aufrufen, wenn mehrere Zeilen verfügbar sind, wird es alle in Ihrem Puffer gelesen, aber wenn Sie dann printf() sie, es wird nur bis zum ersten abschließenden Null gedruckt, so dass Sie nie sehen sie eine der Zeilen danach der erste. Wenn Sie Ihren sleep()-Aufruf hinzufügen, wird verhindert, dass mehr als eine Zeile in die Datei geschrieben wird, bevor der andere Prozess eine Chance auf read() hat. In diesem Fall tritt das Problem nicht auf.

Lösung: Schreiben Sie nicht die abschließende Null in Ihre Textdatei. Zur gleichen Zeit, können Sie Ihren Code ein wenig kompakter machen, indem:

fgets(buffer, BUFFER_SIZE, (FILE*)fp); 
do{ 
    write(fd[1],buffer,strlen(buffer)+1); 
}while(fgets(buffer, BUFFER_SIZE, (FILE*)fp) != NULL); 

zu:

while (fgets(buffer, BUFFER_SIZE, fp)) { 
    write(fd[1], buffer, strlen(buffer)); 
} 

Zweitens, read() nicht null für Sie die Zeichenfolge beenden, so dass, wenn Sie implementieren diese Lösung, dieser Aufruf:

read(fd[0], read_msg, BUFFER_SIZE) 

nicht null beenden read_msg. Die Lösung besteht darin, zu überprüfen, wie viele Bytes read() tatsächlich lesen, und den abschließenden Nullwert nach diesen vielen Bytes manuell hinzuzufügen. Beachten Sie, dass Sie höchstens ein Byte weniger als die Puffergröße lesen müssen, wenn Sie es füllen, da Sie Platz für die abschließende Null benötigen.

Sonstiges:

  1. Sie prüfen nicht, ob fopen() erfolgreich ist, und Sie sollten. Dasselbe gilt für write() und close(). Sie können die Rückgabewerte in anderen Fällen gut überprüfen.

  2. Die Besetzung zu FILE * in fgets(buffer, BUFFER_SIZE, (FILE*)fp) hat keine Auswirkung, da fp bereits von FILE * Typ ist. Es sollte weggelassen werden.

2

See this post ‚s akzeptierte Antwort für eine gute Erklärung, warum fgets hier mit Problemen führen kann.

Sie können den folgenden Ansatz in der Eltern nehmen:

if (pid>0) 
{ 
    int size, file_fd; 
    file_fd = fileno(fp); 

    close(fd[0]); 
    while((size = read(file_fd, buffer, BUFFER_SIZE)) != 0) { 
     write(fd[1],buffer,size); 
     //sleep(1); 
    } 
close(fd[1]); 
wait(NULL); 
} 

Und im Kind:

else{ 
    close(fd[1]); 
    int size; 
    while((size = read(fd[0], read_msg, BUFFER_SIZE)) != 0){ 
     write(1,read_msg, size); 
    } 
    close(fd[0]); 
    } 
    fflush(stdout); 
    fclose(fp); 
    return 0; 
} 

, die in Stücke liest. Beachten Sie, dass ich ersetzt:

printf("Child had read: %s", read_msg); 

Für Konsistenz, da wir untergeordneten Systemaufrufe mit sind, und Dinge kann schwierig, wenn Sie mischen-up I/O wie printf mit Systemaufrufe gepuffert.

Es gibt auch einige andere kleinere Probleme (zB schließen Sie nicht die übergeordnete Datei), und Sie sollten viel mehr Prüfungen beim Lesen/Schreiben ausführen, um zu verifizieren, dass kein Fehler aufgetreten ist, aber dies wird an die Herz Ihres Problems.