Interprozesskommunikation via Pipes in C

Liebe/-r Experte/-in,

Für die Uni muss ich ein Programm schreiben, bei dem das Ergebnis einer Matrixmultiplikation berechnet wird. Dabei soll jede Ergebniszeile in einem eigenen Kindprozess berechnet werden, der dieses Ergebnis dann mittels einer Pipe an den Elternprozess übermittelt.

Mein Programm funktioniert soweit schon ganz gut. Die Ergebnisse werden berechnet und an den Elternprozess übermittelt. Nur bekommt der der Elternprozess scheinbar nur das erste der 5 Ergebnisse und gibt auch nur dieses aus. Da ich mich noch nicht lange mit diesem Thema auseinandersetze, fürchte ich, dass ich einen großen Denkfehler bei dieser Sache mache, deshalb hoffe ich auf diesem Wege auf den richtigen Denkanstoß.

Hier ist der abgespeckte Programmtext mit einigen Kommentaren in dem alles enthalten sein dürfte, was für etwaige Probleme verantwortlich sein könnte:


#define DIM_MATRIX 5
#define MAX_ZEICHEN 32

int main(){

int kind, status, fd[2], i=0, j=0;
float erg[DIM_MATRIX], res;
char zeile[MAX_ZEICHEN], buf[5];
float matrix1[5]={0, 1, 2, 3, 4};
float matrix2[5]={1, 0, 1, 2, 3};
float matrix3[5]={2, 1, 0, 1, 2};
float matrix4[5]={3, 2, 1, 0, 1};
float matrix5[5]={4, 3, 2, 1, 0};
float skal[5] = { 1.25, 0, 0, 0, 0.25 };

if( pipe(fd)

Zunaechst ein paar Sachen die mir aufgefallen sind…

„int q = read…“… da Du q spaeter benutzt muss man normalerweise q im deklarationsteil der funktion deklarieren nicht im Programmcode (ANSI C wuerde da schwierigkeiten machen.

Bei berechnungsergebnis in pipe schreiben schreibst Du 5 Zeichen, liest aber im parent bis zu 32. buf ist etwas Klein…

Du oeffnest die pipe vor der for Schleife, schliesst sie aber in der for schleife. Daher kann nur der erste prozess wirklich was schreiben. Da Du keine Fehler bei read/write abfaengst und diese die Variable Zeile nicht aendern wenn sie Fehler haben (zB Pipe nicht offen) wird ergebnis 0 Richtig und Ergebnisse 1-4 wie 0 sein.

Loesung: Oeffne die Pipe in der for Schleife direkt vor dem Fork.

Tip: Versuche immer gleich Fehlerbehandlung mit einzubauen, spaart normalerweise spaeter Arbeit. Zum Beispiel:

Anstatt:

close(fd[0]);

Schreib:

if(close(fd[0]!=0)
{
printf(„Fehler bei Close“, strerror(errno));
exit(1);
}

Hallo,

Vielen Dank für die schnelle und ausführliche Antwort! Die pipe in der Schleife zu öffnen hat den Fehler nun zum Glück beseitigt und das Programm funktioniert wie es soll. Auch für künftige Programme werde ich mir die Tipps auf jeden Fall zu Herzen nehmen!

Liebe Grüße,

Munis

Hallo Munis,
der Fehler ist meiner Meinung nach, dass du nur eine Pipe benutzt. Du musst in der Kind-Erzeugungsschleife eine Pipe pro Kind erzugen. Das ergibt dann ein Array von Pipes.
Das Warten auf die Kinder erfolgt erst nach der Erzeugungs-Schleife.
Der Elternprozesses wartet dann in einer weiteren Schleife auf die Kinder und liest die Pipes aus.
Man könnte auch mit select() auf alle Pipes parallel warten, aber das ist bei dieser Aufgabenstellung nicht nötig.
Der Elternprozesses wartet in der Schleife erst auf das 1. Kind und macht dann mit den anderen weiter. Die Kinder, die schneller sind, warten dann eben bis der Elternprozess sie abfragt. Das ist automatisch so!
In der Summe ist die Wartezeit dann gleich dem langsamsten Kind - besser geht es ohnehin nicht.
Gruß
Rüdiger

Hallo Munis,

der read-Aufruf im Vaterprozess liest nach dem ersten Wert keinen weiteren. Dadurch wird „zeile“ nicht überschrieben und du bekommst jedes Mal das gleiche Ergebnis.

Da die Behandlung von „high-level“ streams deutlich einfacher ist, habe ich dein Programm dahingehend abgewandelt, dass im Kindprozess der schreibbare FD der pipe auf stdout gelegt wird (damit ein einfacher printf-Aufruf an den Vater sendet) und im Vaterprozess ein FILE* mit der lesbaren FD der pipe geöffnet wird:

Kind:
close(1); // stdout schließen
dup2(fd[1], 1); // fd[1] „kopiert“ den schreibbaren FD der pipe auf eine neue FD-Nummer

Ein deutlicheres Problem deines Programmaufbaus ist aber, dass der Vaterprozess auf das aktuelle Kind wartet, bevor er das nächste erzeugt. Dadurch führt dein Programm keine parallelen Berechnungen durch und du hättest den gleichen erfolg bei der Arbeit in einem einzelnen Prozess.

Das übliche Vorgehen für parallele Berechnungen ist, dass der Vaterprozess zunächst alle Kindprozesse erstellt und erst danach auf die Ergebnisse wartet (also außerhalb der for-Schleife).

Da die Ergebnisse in „zufälliger“ Reihenfolge (abhängig von der unterschiedlichen Berechnungszeit der Zeilen und vom Betriebssystem) gemeldet werden, solltest du zusätzlich die Ergebnisse mit der Zeilennummer identifizieren.

Erstellen der Prozesse. Alle Kindprozesse werden ohne Wartezeit direkt hintereinander erstellt und fangen ihre berechnungen an:
for(i=0; i= DIM_MATRIX)
printf(„ungültige Zeile: %d\n“, zeilennr);
else
erg[zeilennr] = wert;

kind=wait(&status); //warte bis Kindprozess beendet
printf(„Kind %d fertig\n“, kind);
}
close(fd[1]);

Bei meinen Tests lieferte das Programm die richtigen Werte in der richtigen Reihenfolge.

Grüße
Karsten

hi munis
also auf den ersten blick durchschaue ich dein programmfragment nicht und sehe somit auch keine fehler. es wäre sinnvoll mir das programm komplett zu schicken. ebenfalls können informationen zu verwendeten bibliotheken, bzw zur runtimeumgebung hilfreich sein.
ich erwarte deine mail
gruß
adi

adolf dot goering at usa dot net - du weißt was das ist…

Hallo Munis,

Liebe/-r Experte/-in,

Für die Uni muss ich ein Programm schreiben, bei dem das
Ergebnis einer Matrixmultiplikation berechnet wird. Dabei soll
jede Ergebniszeile in einem eigenen Kindprozess berechnet
werden, der dieses Ergebnis dann mittels einer Pipe an den
Elternprozess übermittelt.

Mein Programm funktioniert soweit schon ganz gut. Die
Ergebnisse werden berechnet und an den Elternprozess
übermittelt. Nur bekommt der der Elternprozess scheinbar nur
das erste der 5 Ergebnisse und gibt auch nur dieses aus. Da
ich mich noch nicht lange mit diesem Thema auseinandersetze,
fürchte ich, dass ich einen großen Denkfehler bei dieser Sache
mache, deshalb hoffe ich auf diesem Wege auf den richtigen
Denkanstoß.

Hier ist der abgespeckte Programmtext mit einigen Kommentaren
in dem alles enthalten sein dürfte, was für etwaige Probleme
verantwortlich sein könnte:

Mir ist auch klar, dass man das ganze sicherlich mittels
Zeigern eleganter und einfacher lösen könnte, leider habe ich
von diesen jedoch noch keine große Ahnung und hoffe, das
Programm auch so ans Laufen zu bekommen!

Vielen Dank bereits im Voraus!

Liebe Grüße,

Munis

Leider kann ich nicht weiterhelfen.

MfG
Michael Kunkel