ein Kapitel zurück                                           ein Kapitel weiter

Natürlich können sie mit Pipes auch eine Multiplexing-Ein/Ausgabe reallisieren. In diesem Fall müssen wir 2 Pipes erzeugen.

/*Download:pip3.c*/
#include <unistd.h> #include <sys/wait.h> #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #define MAX 512 enum { READ,WRITE}; int main(int argc, char **argv) { char *fname; int fdout[2], fdin[2]; int fd, n; char puffer[MAX]; /*Wir erzeugen 2 Pipes*/ if(pipe(fdout) <0 || pipe(fdin) <0) { perror("pipe : "); exit(0); } /*Nun erzeugen wir einen neuen Prozeß*/ switch(fork()) { case -1 : perror("fork : "); exit(0); case 0 : /*Im Kindprozess*/ close(0); /*stdin schließen*/ dup(fdout[READ]); /*Lese-Deskriptor duplizieren*/ close(1); /*stdout schließen*/ dup(fdin[WRITE]); /*Schreib-Deskriptor duplizieren*/ /*Kindprozess wird von grep überlagert daher benötigen wir diese Deskriptoren nicht mehr. Alle Vorsorgen haben wir eben gemacht...*/ close(fdout[READ]); close(fdout[WRITE]); close(fdin[READ]); close(fdin[WRITE]); /*Nach dieser Zeile wird der Kindprozeß überlagert....*/ execlp("grep", "grep", "^#include", NULL); default : /*Elternprozeß*/ close(fdout[READ]); /*Elternprozeß schreibt nur in die Pipe fdout*/ close(fdin[WRITE]); /*Elternprozeß liest nur von Pipe fdin aus grep*/ /*Datei öffnen*/ fd=open(argv[1], O_RDONLY); if(fd < 0) { perror("open : "); exit(0); } /*Aus Datei lesen*/ while((n = read(fd, puffer, MAX)) != 0) { if(n==-1) exit(0); /*Wir schreiben etwas in die Pipe fdout an grep*/ if(write(fdout[WRITE], puffer, n) == -1) { perror("write : "); exit(0); } } /*Datei schließen*/ close(fd); /*Schreibseite schließen*/ close(fdout[WRITE]); /*Das ist das Zeichen für grep zum lesen aus der Pipe fdout*/ /*Nun wollen wir lesen was grep mit unseren Daten gemacht hat*/ /*read blockiert solange bis grep fertig ist*/ while(( n=read(fdin[READ], puffer, MAX)) != 0) { if(n==-1) exit(0); /*Jetzt wollen wir das ganze auf dem Bildschirm ausgeben*/ if(write(STDOUT_FILENO,puffer, n) == -1) { perror("write :"); exit(0); } } /*Jetzt noch die Leseseite schließen wir sind fertig*/ close(fdin[READ]); } return 0; }

Entscheident ist im Kindprozeß das Duplizieren des Filedeskriptors. Wie sie im Kapitel dup und dup2 bereits gelernt haben bleibt mit Hilfe der dup-Funktion das close-on-exec-Flag gelöscht bei einem exec-Aufruf. Wir verbinden praktisch mit der Funktion dup die Standardaus/eingabekanäle mit unseren Pipekanälen. Wichtig ist in einem solchen Fall, wenn wir unseren Kindprozeß überlagern die Reihenfolge: fork, close, dup, exec. Somit kommuniziert unser aktuell laufender Elternprozeß mit dem Programm grep und Filter alle Zeilen die mit '#include' Beginnen aus auf dem Bildschirm.

Hier sehen das ganze nochmals Bildlich..........




Mit 2 Pipes sind wir außerdem in der Lage 2 Prozesse zu Syncronisieren, ähnlich wie bei dem Kapitel der Signale. In diesem Falle kommt uns das Blockieren der Funktion read zugute. Folgendermaßen können sie die Syncronisation von Prozesse mit Pipes erledigen...........

/*Download:pipsyn.c*/
int eltern_kind_pipe[2], kind_eltern_pipe[2]; void INIT_SYNC(void) { if(pipe(eltern_kind_pipe) < 0 || pipe(kind_eltern_pipe) < 0) EXIT("Fehler beim Initialisieren der Pipes........"); } void bin_fertig_papa(pid_t pid) { if(write(kind_eltern_pipe[1], "k", 1) !=1) EXIT("Fehler bei write.............."); } void bin_fertig_kind(pid_t pid) { if(write(eltern_kind_pipe[1], "e", 1) != 1) EXIT("Fehler bei write......."); } void warte_auf_papa(void) { char zeichen; if(read(eltern_kind_pipe[0], &zeichen, 1) != 1) EXIT("Fehler bei read.........."); if(zeichen!='e') /*Kind erwartet das Zeichen 'e' */ EXIT("Fehler bei warte_auf_papa......"); } void warte_auf_kind(void) { char zeichen; if(read(kind_eltern_pipe[0], &zeichen, 1) != 1) EXIT("Fehler bei read.........."); if(zeichen!='k') /*Eltern erwarten das Zeichen 'k' */ EXIT("Fehler bei warte_auf_kind......"); }

ein Kapitel zurück          nach oben           ein Kapitel weiter


© 2001,2002 Jürgen Wolf