Linux Pipes - Unregelmaessiges Problem

xellsys

Grünschnabel
Hi,
Ich habe ein Programm geschrieben mit dem der Inhalt zweier Text-dateien unter Linux vertauscht wird. Das ganze lasse ich ueber 2 Prozesse laufen, die miteinander ueber eine unnamed pipe kommunizieren.
Das Problem ist, dass das Programm scheinbar willkuerlich nicht funktioniert.
In einem folder erstell ich 2 Textdateien (a,b) mit Inhalt 'a\nb\nc' und 'x\ny\nz\n' und versuche die zu vertauschen und es klappt. Dann verschiebe ich alle 3 Dateien (a.out, a, b) in einen anderen folder und es geht nicht mehr, die beiden Dateien sind danach einfach leer, halt als wenn sie zum schreiben geoeffnet wurden, nur es wurde halt nix reingeschrieben.
Ich hoffe mir kann jemand helfen, vielen dank :)
Hier ist mein code:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#define line_length 1000

int fd[2],fd2[2];
FILE *file1,*file2,*pipe1,*pipe2;

void clean_up(int sig)
{
    close(fd[0]);
    close(fd2[0]);
    close(fd2[1]);
    close(fd[1]);
    fclose(pipe1);
    fclose(pipe2);
    exit(EXIT_SUCCESS);
}

int main(int argc,char* argv[])
{
    int opt,pid,check=-2;
    char *file1_path = NULL,*file2_path = NULL,line1[line_length],line2[line_length];
    
    (void) signal(SIGHUP, clean_up);
    (void) signal(SIGINT, clean_up);
    (void) signal(SIGQUIT, clean_up);
    (void) signal(SIGTERM, clean_up);
        
    if(argc != 3)
    {
        fprintf(stderr,"wrong number of arguments\n");
        return 1;
    }
    file1_path = argv[1];
    file2_path = argv[2];
    
    if(pipe(fd))
    {
        fprintf(stderr,"pipe creation failure");
        return 1;
    }
    if(pipe(fd2))
    {
        fprintf(stderr,"pipe2 creation failure");
    }
    
    pid = fork();
    switch(pid)
    {
        case -1: fprintf(stderr,"process failure\n"); break;
        case 0:                                                 //CHILD PROCESS:READ STRING FROM FILE -> PUT STRING INTO PIPE 
        
        fprintf(stdout,"child process established\n"); 
        
        close(fd[0]);  // pipe 1 zum lesen schliessen
        close(fd2[0]); // pipe 2 zum lesen schliessen
        if(!(file1 = fopen(file1_path,"r")))
            fprintf(stderr,"fehler beim erstellen der datei 1 zum lesen");  //datei 1 zum lesen oeffnen
        if(!(file2 = fopen(file2_path,"r")))
            fprintf(stderr,"fehler beim erstellen der datei 2 zum lesen");  //datei 2 zum lesen oeffnen
        
        if((pipe1 = fdopen(fd[1],"w"))==NULL) // pipe 1 zum schreiben oeffnen
        {
            fprintf(stderr,"writepipe1 creation failure");
            return 1;
        }
        if((pipe2 = fdopen(fd2[1],"w"))==NULL) // pipe 2 zum schreiben oeffnen
        {
            fprintf(stderr,"writepipe2 creation failure");
            return 1;
        }
                
        while(check) 
        {
            if(fgets(line1,line_length,file1))  // zeile aus datei 1 lesen
            {
                fputs(line1,pipe1); // diese zeile in die pipe1 schreiben
                fflush(pipe1);
            }
            else if(check == -1) check = 0;
            else if(check != 0) check = -1;
            if(fgets(line2,line_length,file2)) // zeile aus datei 2 lesen
            {
                fputs(line2,pipe2); // diese zeile in die pipe 2 schreiben
                fflush(pipe2);
            }
            else if(check == -1) check = 0;
            else if(check != 0) check = -1;
            //write(fd[1],line,line_length);
        }
        close(fd[1]);
        close(fd2[1]);
        fclose(file1);
        fclose(file2);
        break;
        
                
        default:                                                //FATHER PROCESS: READ STRING FROM PIPE -> PUT STRING INTO FILE
        
        fprintf(stdout,"father process established\n"); 
        
        close(fd[1]); // pipe 1 zum schreiben schliessen
        close(fd2[1]); // pipe 2 zum schreiben schliessen
        if(!(file1 = fopen(file1_path,"w+")))
            fprintf(stderr,"fehler beim erstellen der datei 1 zum schreiben");  // datei 1 zum schreiben oeffnen
        if(!(file2 = fopen(file2_path,"w+")))
            fprintf(stderr,"fehler beim erstellen der datei 2 zum schreiben");;  // datei 2 zum schreiben oeffnen
        
        if((pipe1 = fdopen(fd[0],"r"))==NULL)  // pipe 1 zum lesen oeffnen
        {
            fprintf(stderr,"readpipe creation failure");
        }
        if((pipe2 = fdopen(fd2[0],"r"))==NULL) // pipe 2 zum lesen oeffnen
        {
            fprintf(stderr,"readpipe creation failure");
        }
        while(check) 
        {
            if(fgets(line1,line_length,pipe1)) // zeile aus pipe 1 lesen
            {
                fputs(line1,file2); // diese zeile in datei 1 schreiben
                //fputs(line1,stdout);
                fflush(file2);
            }
            else if(check == -1) check = 0;
            else if(check != 0) check = -1;
            if(fgets(line2,line_length,pipe2)) // zeile aus pipe 2 lesen
            {
                fputs(line2,file1); // diese zeile in datei 2 schreiben
                //fputs(line2,stdout);
                fflush(file1);
            }
            else if(check == -1) check = 0;
            else if(check != 0) check = -1;
            //write(fd[1],line,line_length);
        }
        close(fd[0]);
        close(fd2[0]);
        fclose(file1);
        fclose(file2);
        break;
    }
    fclose(pipe1);
    fclose(pipe2);
    if(pid!=0) fprintf(stdout,"file copy successfull\n");
    return 0;
}
PS: Ausserdem scheint es mir Sonderzeichen in den Textdateien gar nicht zu funktionieren....warum auch immer
 
Zuletzt bearbeitet:
Hallo,

das liegt daran das deine Prozesse nicht synchronisiert sind. Bevor dein Vaterprozess die Dateien zum Schreiben öffnen kann muss er solange warten bis das Kind sämtliche Infos in die beiden Pipes geschrieben und die Dateien sauber geschlossen hat. Ansonsten öffnet der Vater die Dateien zu früh und sie werden vom Vater gestutzt ("w+").

xellsys hat gesagt.:
PS: Ausserdem scheint es mir Sonderzeichen in den Textdateien gar nicht zu funktionieren....warum auch immer

Was funktioniert denn nicht? Gibt es Fehlermeldungen was sind die Symptome?

Gruß,
RedWing
 
Nja, wie gesagt in dem einen Ordner funktioniert es ohne Probleme bei 2 Dateien (abc und xyz).
Bzgl. der Sonderzeichen, werden die beiden Textdateien einfach geleert, wird halt nix reingeschrieben.
Ich hab auch schon daran gedacht, dass es am fehlenden Synchronisieren liegt.
Am besten waers, wenn der Vaterprozess erst beginnt wenn er die Terminierung vom child Prozess oder?
Wenn ich jedoch die pipe von der child Seite aus schliesse (bevor das child terminiert) dann kann der vater Prozess doch nicht mehr aus der pipe lesen oder?

edit: ok ich hab jetzt einfach mal zum testen ein sleep(5); vor die Berechnungen des vater Prozesses eingefuegt und es scheint zu funktionieren. Daher liegt es wohl an der mangelnden Synchronisation. Ausserdem kann er trotzdem noch aus der pipe lesen obwohl das child terminiert ist und seinen teil der pipe komplett geschlossen hat. Gut zu wissen, danke.
Werde jetzt versuchen einfach mit dem Terminierungssignal des child's beim vater Prozess zu starten.

edit2: Super, habs jetzt mithilfe von:
Code:
        if ((waitpid (pid, NULL, 0)) < 0) 
        {
            perror ("waitpid");
            exit (EXIT_FAILURE);
        }
synchronisiert und klappt scheinbar einwandfrei :D
Werde es jetzt noch ein wenig testen,
Vielen Dank!
 
Zuletzt bearbeitet:
Hallo,

Am besten waers, wenn der Vaterprozess erst beginnt wenn er die Terminierung vom child Prozess oder?
Ja genau.
Wenn ich jedoch die pipe von der child Seite aus schliesse (bevor das child terminiert) dann kann der vater Prozess doch nicht mehr aus der pipe lesen oder?
Mhm ganz sicher bin ich mir da leider nicht:
Ich denke die Dateidiskreptoren für die Pipes werden mit dem fork kopiert. Da der Vater also dementsprechend noch offene Referenzen auf die Pipes hält, sollten die Ressourcen nach dem Schließen der Pipes durch das Kind vom BS gehalten werden. In der Doku von pipe steht folgendes:
"Data written to the write end of the pipe is buffered by the kernel until it is read from the read end of the pipe."
Berücksichtigt man diese Punkte, sollte es funktionieren.

Bzgl. der Sonderzeichen, werden die beiden Textdateien einfach geleert, wird halt nix reingeschrieben.
Bei mir funktioniert es auch mit Sonderzeichen solange ich die Prozesse wie oben beschrieben synchronisiere.

Gruß,
RedWing
 
edit: ok ich hab jetzt einfach mal zum testen ein sleep(5); vor die Berechnungen des vater Prozesses eingefuegt und es scheint zu funktionieren. Daher liegt es wohl an der mangelnden Synchronisation. Ausserdem kann er trotzdem noch aus der pipe lesen obwohl das child terminiert ist und seinen teil der pipe komplett geschlossen hat. Gut zu wissen, danke.
Werde jetzt versuchen einfach mit dem Terminierungssignal des child's beim vater Prozess zu starten.

edit2: Super, habs jetzt mithilfe von:
Code:
        if ((waitpid (pid, NULL, 0)) < 0) 
        {
            perror ("waitpid");
            exit (EXIT_FAILURE);
        }
synchronisiert und klappt scheinbar einwandfrei :D
Werde es jetzt noch ein wenig testen,
Vielen Dank!

Schön das ich helfen konnte. Wegen dem funktionierenden Lesen der Pipes siehe Vorpost.

//edit: Noch was: Du solltest deinen 2ten Dateideskriptor vlt. nicht grad pipe2 nennen denn so heißt schon die interne Funktion zum Anlegen von Pipes welche nicht POSIX konform ist. Wenn ich deinen Source mit -Wall übersetze bekomm ich auch entsprechend eine Warnung.

Gruß,
RedWing
 
Zuletzt bearbeitet:
Hi.

Du solltest evtl. auch bedenken, das eine Pipe lediglich einen recht kleinen Puffer (64 KiB) hat und du auf diese Weise nur den Inhalt der Dateien tauschen kannst, wenn der komplette Dateiinhalt in die Pipes passt.

Gruß

PS: Bitte beachte die Netiquette, Punkt 15, Groß-/Kleinschreibung. Danke!
 
Zuletzt bearbeitet:
jo das mit dem pipe buffer stimmt allerdings.
bzgl der pipe2 variable, werd ich diese aendern, danke.
hatte bisher nur ueber make kompiliert und so :]
 
Zurück