|
![ein Kapitel weiter](../weiter.gif)
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 weiter](../weiter.gif)
© 2001,2002 Jürgen Wolf
|