Ist es möglich, eine Pipe zwischen zwei untergeordneten Prozessen zu haben, die von demselben Elternteil erstellt wurden (LINUX, POSIX)?

8

Ich habe mehrere Kind "gegabelt" von der gleichen Eltern und ich versuche, pipe Verbindung zwischen all diesen Kind-Prozesse wie eine verkettete Liste Struktur zu konstruieren. Child 1 sendet Daten an child2, child 2 an child 3 .... child N an child 1. Gibt es einen geeigneten Weg, dies zu tun?

Außerdem, wenn ich zwischen den Prozessen erstelle und kommuniziere, erzwinge ich, dass der Elternteil den gesamten Prozess "wartet", bis wait() oder waitpid() auf den ersten abgeschlossenen Prozess wartet, aber ich muss auf alle warten. Es ist die andere Frage, die sich stellt.

Danke ...

    
erogol 07.03.2011, 22:03
quelle

3 Antworten

17

Dies ist im Wesentlichen das, was eine Shell macht, wenn sie eine Umleitungskette erstellt, d. h. so etwas wie

%Vor%

Es gibt einige ausgezeichnete einführende Texte zur Unix-Programmierung, in denen eine einfache Shell durch das Buch implementiert wird. Und eine der Aufgaben einer Shell ist die Umleitung. Eines dieser Bücher ist "Linux Application Programming" von Michael K. Johnson und Erik W. Troan.

Die Homepage des Buches: Ссылка

Um eine Kette von Umleitungen für N Prozesse zu erstellen, benötigen Sie N-1 Pipes. Für jede Umleitung erstellen Sie eine Rohrleitung mit dem Systemaufruf pipe(int fds[2]) . Nach fork() ing, aber vor execv ing verwenden Sie dup2(int from, int to) , um das Ende einer Pipe mit der Standardeingabe (0) oder der Standardausgabe jedes Prozesses zu verbinden. Hier ist ein übermäßig vereinfachter Code, ohne Fehler zu überprüfen:

%Vor%

Beachten Sie, dass die Array-Indizes der Pipe so ausgewählt wurden, dass sie die standardmäßigen Eingabe- / Ausgabedateideskriptoren widerspiegeln, wenn sie für die Umleitung von Standardwerten verwendet werden. Diese Wahl war nicht willkürlich.

Natürlich können Sie Pipes mit beliebigen Dateideskriptoren verbinden (zB gibt es Anwendungen, die erwarten, dass ihr Elternteil geöffnet wird, sagen fd 3 und 4, verbunden mit Pipes) und die meisten Shells unterstützen das auch direkt (zum Beispiel 1 & gt; & amp; 3 wird stdout in fd umleiten 3). Die Array-Indizes für pipe(int fds[2]) sind natürlich 0 und 1. Ich erzähle das nur, weil ich ein paar Cargo-Cult-Programmierstudenten hatte, die gedankenlos die Ziel-FDS auch für das Pipe-Syscall-Array mitnahmen.

Um darauf zu warten, dass alle Kinder waitpid(-1, NULL, 0) beenden - ich denke, das ist der Wert -1, den mein Vorbeantworter gemeint hat, was bedeutet: Warte, bis alle untergeordneten Prozesse beendet sind. Die andere Option war wait() in einer Schleife aufzurufen, die die PID des gerade beendeten Kinds zurückgibt. Wenn es erneut angerufen wird und noch ein Kind läuft, wird es erneut blockiert. Wenn kein Kind mehr übrig ist, wird -1 zurückgegeben. Ich bevorzuge die waitpid Lösung.

    
datenwolf 07.03.2011, 22:51
quelle
3

Ja, das ist ziemlich einfach, Sie müssen nur alle Pipes im Parent erstellen, und vergessen Sie nicht, die Pipes / Enden der Pipes in den Childs zu schließen, in denen Sie sie nicht brauchen.

>

Das Verlassen von FDs der Pipes bei Kindern, die sie nicht benutzen, ist ein FAIL, da es andere für das Ende der Pipe warten lassen kann. Alle Autoren müssen schließen, bevor der Leser ein EOF erhält.

    
MarkR 08.03.2011 07:23
quelle
2

Erstellen Sie zuerst alle Pipes und dann alle untergeordneten Elemente mit den entsprechenden Pipe-Enden in den FDs 0 und 1.

Warten Sie einfach weiter, bis es -1 zurückgibt.

    
Ignacio Vazquez-Abrams 07.03.2011 22:05
quelle

Tags und Links