2016-06-18 8 views
2

Meine Frage ist, wie man die Prozessausführung in Bezug auf Rohre und speziell die Implementierung der wait/waitpid Funktion steuert.C in Unix: Gabel, waitpid und Rohre

Wenn ich eine Pfeife für den folgenden Befehl ls | head -3, ich folgenden:

  • ich das Rohr schaffen, Gabel des Prozesses
  • Für das Kind, ein Kind zu schaffen, ich nenne dup2 für stdin, I führe den head -3 Befehl Ausgangsseite des Rohrs in dem
  • für die Eltern-Kind-Schließen, ich rufe dup2 für stdout, führe ich den ls Befehl, Schließen die Eingangsseite des Rohres in den übergeordneten

Meine Frage: based on this discussion, ich muss warten, bis das Kind die Ausführung abgeschlossen hat, d. H. Die Ausführung von head -3. Aber wie/wo kann ich die waitpid Funktion so implementieren, dass sie nicht in Konflikt mit dem close[] Befehl steht?

Basierend auf this great text, die Beschreibung lautet:

Wenn die Eltern wollen Daten aus dem Kind zu erhalten, sollte es FD1 schließen, und das Kind sollte fd0 schließen. Wenn das übergeordnete Element Daten an das untergeordnete Element senden möchte, sollte es fd0 schließen, und das untergeordnete Element sollte fd1 schließen. Da die Deskriptoren zwischen dem Elternteil und dem Kind geteilt werden, sollten wir immer sicher sein, das Ende des Rohrs zu schließen, mit dem wir uns nicht befassen. In einer technischen Anmerkung wird der EOF niemals zurückgegeben, wenn die unnötigen Enden der Pipe nicht explizit geschlossen werden.

So muss das Kind auf die Eltern warten, um die Pipe vor der Ausführung abzuschließen.

Ich habe auch Beispiele gesehen, wo zwei Gabeln für einen Prozess mit Rohr hergestellt werden. Kann es der Zweck sein, Zombie-Prozesse zu vermeiden, genau wie die Beschreibung in meiner Kopie von APUE ch.8?

Betrachten Sie den folgenden Code-Implementierung:

#include <stdlib.h> 
    #include <stdio.h> 
    #include <sys/wait.h> 
    #include <sys/types.h> 

    int main() 
    { 
    int pid, status; 

    int fd[2]; 

    char *com1[2]; 
    char *com2[3]; 

    com1[0] = "ls"; 
    com1[1] = NULL; 

    com2[0] = "head"; 
    com2[1] = "-3"; 
    com2[2] = NULL; 

    pipe(fd); 

    if((pid = fork()) == -1) 
    { 
     printf("fork error"); 
     exit(1); 
    } 

    if(pid == 0) 
    { 
     /* Child process closes up output side of pipe */ 
     dup2(fd[0], 0); 
     close(fd[1]); 
     execvp(com2[0], com2); 
    } 

    else 
    { 

     /* if(waitpid(0, WIFEXITED(&status), 0) != pid) 
     { 
      printf("wait error"); 
     } 
     is this even needed here? */ 

     /* Parent process closes up input side of pipe */ 
     dup2(fd[1], 1); 
     close(fd[0]); 
     execvp(com1[0], com1); 

    } 

    exit(0); 

} 

Ich muss zugeben, dass ich durch viele ähnliche Fragen auf Stack hier ausgesehen haben. Fast alle von ihnen sind jedoch von besonderem Inhalt. Nach was ich suche, sind Erklärungen von Prinzipien und Kombinationen der Funktionen. Vielen Dank für Ihre Zeit!

+3

Wenn Sie wollen, dass der übergeordnete Prozess Ausführung fortzusetzen, Sie müssen * zwei * untergeordnete Prozesse erstellen: einen für den Befehl "ls" und einen für den Befehl "head". Und nein das Kind (in Ihrem Programm) muss nicht auf das Elternteil warten, wenn es nichts gibt, das zurzeit aus dem Rohr zu lesen ist, werden alle blockierungsfreien Lesungen (die die Standardeinstellung sind) einfach blockieren, bis Daten zu lesen sind oder ein Fehler tritt ein. –

+1

@JoachimPileborg: "Alle nicht blockierenden Messwerte werden blockiert"? –

+0

Ehm ... Alle non non-blocking reads werden blockieren Ich meine ... :) –

Antwort

0

Sie können nicht beide auf ein Kind und Exec warten. Du musst also zwei Kinder haben. Es gibt zwei gebräuchliche Methoden: Entweder haben Sie einen Elternprozess, der zwei direkte Kinder erstellt, und können/müssen dann auf beide warten. oder ein Kind haben, das selbst das zweite erzeugt, so dass die Eltern nur auf einen Prozessabbruch warten müssen.

Option 1 (geerbt Rohr)

pipe(pi); 
pid1 = fork(); 
if (pid1==0) { // child1 
    // make redirections 
    exec("head"...); 
} 
pid2 = fork(); 
if (pid2==0) { // child2 
    // make redirections 
    exec("ls"...); 
} 
// parent process 
// close unuseful pipe 
waitpid(pid1...); 
waitpid(pid2...); 

Option 2 (Rohr nur sichtbar für die betroffenen Prozesse ist)

pid1 = fork(); 
if (pid1==0) { // child 
    pipe(pi); 
    pid2 = fork(); 
    if (pid2==0) { // gran child 
    // make redirections 
    exec("ls"...); 
    } 
    // make redirections 
    exec("head"...); 
} 
// parent process 
waitpid(pid1...); 
+0

"habe ein Kind, das selbst den zweiten erstellt" Wer wird dann auf den zweiten warten? Es ist die gleiche Situation wie bei einem Kind. –

+0

Zwei Kinder ist nicht die gleiche Situation wie ein Kind, offensichtlich (der Hauptvorteil ist, dass die Eltern jetzt warten können ...). All dies sollte in einer Prozessgruppe enthalten sein, einfacher zu verwalten, aber es ist eine andere Geschichte ... –

+0

In Ihrem zweiten Snippet haben Sie nur eine Wartezeit. Wohin geht der zweite? –