LordBen
Anmeldungsdatum: 17. Juni 2009
Beiträge: 19
|
Hallo zusammen. Ich habe folgendes C-Programm: #include <stdio.h>
int cnt = 0;
int main(void) {
int fork_pid = getppid();
int my_pid = -1;
my_pid = getpid();
printf("cnt = %d, fork_pid = %5d, my_pid = %5d\n",
cnt, fork_pid, getpid());
fork_pid = fork();
cnt++;
printf("cnt = %d, fork_pid = %5d, my_pid = %5d\n",
cnt, fork_pid, getpid());
fork_pid = fork();
cnt++;
printf("cnt = %d, fork_pid = %5d, my_pid = %5d\n",
cnt, fork_pid, getpid());
} Wie es zur Ausgabe des Programms kommt ist mir soweit klar, mir wurde dazu bereits im Thread http://forum.ubuntuusers.de/topic/verstaendnissproblem-mit-c-programm/#post-2677470 geholfen. Nun möchte ich das Programm folgendermaßen aufrufen:
./programm | cat - Das Programm liefert mir dabei 12 Ausgabezeilen die so aussehen können:
cnt = 0, fork_pid = 9074, my_pid = 9966
cnt = 1, fork_pid = 0, my_pid = 9968
cnt = 2, fork_pid = 0, my_pid = 9969
cnt = 0, fork_pid = 9074, my_pid = 9966
cnt = 1, fork_pid = 9968, my_pid = 9966
cnt = 2, fork_pid = 0, my_pid = 9970
cnt = 0, fork_pid = 9074, my_pid = 9966
cnt = 1, fork_pid = 0, my_pid = 9968
cnt = 2, fork_pid = 9969, my_pid = 9968
cnt = 0, fork_pid = 9074, my_pid = 9966
cnt = 1, fork_pid = 9968, my_pid = 9966
cnt = 2, fork_pid = 9970, my_pid = 9966 Ich verstehe allerdings nicht wie es zu dieser Ausgabe kommt. Ich dachte der Pipe-Befehl würde zur Kommunikation zwischen Prozessen dienen und in diesem Fall die Ausgabe des Programms als Eingabe an den cat-Befehl weiterleiten. Auf der Manualpage zu cat steht:"concatenate files and print on the standard output". Ich übergebe cat aber nur die Ausgabe des Programms, ich brauche aber doch eigentlich zwei Eingaben um etwas zu konkatenieren, oder?
Ich fürchte ich habe irgendwo einen Denkfehler. Kann mir jemand einen Tipp geben worans liegt? Grüße,
ben
|
John_W
Anmeldungsdatum: 10. Juli 2010
Beiträge: 571
|
Mit cat kannst du beliebig viele Eingabeströme (naja, mindenstens einen) verbinden; - ist die Kurzform für /dev/stdin (wird leider nicht von allen Programmen erkannt). Du könntest genauso gut auch "./programm | cat" schreiben, also ohne -, weil cat Standardmäßig von der Standardeingabe liest, wenn kein Dateiname übergeben wird. Die Pipe verbindet einen Ausgabestrom (/dev/stdout) mit einem Eingabestrom (/dev/stdin).
|
Doc_Symbiosis
Anmeldungsdatum: 11. Oktober 2006
Beiträge: 4453
Wohnort: Göttingen
|
Hm, was möchtest Du denn genau machen. Also so, wie Du den Befehl hingeschrieben hast, reichst Du die Ausgabe des Programms, die auf Stadradausgabe ausgegeben wird an cat weiter und gibt's hierüber die Ausgabe auf der Standardausgabe aus.
Es würde also an der Ausgabe nichts verändern, wenn ich das so richtig sehe.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Hi Ben, was willst Du denn überhaupt bezwecken, oder was erwartest Du ? - so ein " | cat - " ist ja an sich ziemlich sinnlos, es sei denn Du wolltest mehrere Dateien zu einer vereinen. Und eine Pipe verknüpft verschiedene Programme nur in dem Sinn, dass die (stdout-) Ausgabe des ersten in die (stdin-) Eingabe des nächsten gefüttert wird. Nicht mehr und nicht weniger. LG, track
|
LordBen
(Themenstarter)
Anmeldungsdatum: 17. Juni 2009
Beiträge: 19
|
Danke für die Antworten. Doc_Symbiosis schrieb: Hm, was möchtest Du denn genau machen. Also so, wie Du den Befehl hingeschrieben hast, reichst Du die Ausgabe des Programms, die auf Stadradausgabe ausgegeben wird an cat weiter und gibt's hierüber die Ausgabe auf der Standardausgabe aus.
Es würde also an der Ausgabe nichts verändern, wenn ich das so richtig sehe.
Das dachte ich mir auch. Aber die Ausgabe verändert sich, das Programm gibt ohne zusätzliche Parameter 7 Zeilen aus, in Verbindung mit "| cat - 12" Zeilen.
Ich kann aber nicht nachvollziehen warum bzw. wie sich die Ausgabe verändert.
Über den Sinn kann ich (noch) nichts sagen, es handelt sich dabei um ein Beispiel aus der Uni, welches mir wohl die Verwendung von Pipes in Verbindung mit fork() näherbringen soll.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Das liegt dann aber an dem Programm, würde ich mal sagen. Denn das kann natürlich abfragen, ob es seine Ausgabe in eine Pipe einspeist, und deshalb dann z.B. was ganz anderes machen ... Mit "Nassem Finger" lässt sich also nichts weiter sagen. Aber du könntest ja mal das Programm (oder einen Link) posten, vielleicht wird dann irgend was deutlich. ... sorry, nicht richtig aufgepasst. (John W, Du hast ja Recht. 😳) Also das Programm nochmal genauer angucken.... LG, track
|
John_W
Anmeldungsdatum: 10. Juli 2010
Beiträge: 571
|
du könntest ja mal das Programm (oder einen Link) posten, vielleicht wird dann irgend was deutlich.
Öhmm... hat er doch im ersten Post?!
|
theinlein
Anmeldungsdatum: 29. Dezember 2007
Beiträge: 1279
|
Hi, also, wenn ein (Vater-)Prozess sich forked, dann dupliziert er sich mit samt seinem momentanen Zustand; d.h. der Kindprozess läuft an der Stelle weiter, an der sein Vater im Moment der forks auch stand. Dein Prozess läuft los und verursacht (wenn man die Kindprozesse erst mal weglässt) 3 Ausgabezeilen. Nach dem ersten printf erfolgt ein fork, ein Kindprozess startet an eben dieser Stelle - der wird also nur noch 2 Zeilen ausgeben, weil der fork nach dem ersten printf stattfand. Das heißt auch, dass dieser Kindprozess nur noch einmal forked und nur noch ein Kindprozess erzeugt mit einem printf ohne weiteren fork. Das sind zunächst 3 weitere Zeilen von zwei Kind bzw. Enkelprozessen. Zurück zum ursprünglichen Vater: der hat auch noch einen weiteren fork und startet einen weiteren Kindprozess, der aber nicht mehr forked und nur eine Zeile ausgibt. Das macht an der Stelle eine Zeile zusätzlich zum Vater. Das sind also 3 + 3 (vin Kind/Enkel) und 1 vom letzten Kind –> also 7 DEINE cat-Ausgabe: Da tauchen Ausgaben mehrfach auf z.B. PPID=9074 PID=9966 3 mal und
cnt = 0, fork_pid = 9074, my_pid = 9966
cnt = 1, fork_pid = 9968, my_pid = 9966
PID 9966 hat zwei Väter. Das ist nun gar nicht zu erklären, weil in dem Moment, in dem sich ein Vater verabschiedet, die PPID zu Null wird. Irgenwo hast du Murks gebaut.
Oder stehe ich da auf'm Schlauch?
|
theinlein
Anmeldungsdatum: 29. Dezember 2007
Beiträge: 1279
|
Ach, jetzt weiß ich wo ICH auf'm Schlauch steh': die PPID wird ja nur bei m ersten mal beim Vater ausgegeben, sonst ist es die gerade erzeugt Kind-PID. Also die Ausgaben wiederholen sich mit dem 'cat -' weil das Minuszeichen eine weitere "Datei" ist, die dann zusätzlich geöffnet wird. Insofern kommt der Kram zweimal, bis auf das, was nicht mehr kommt, weil der zweite Kanal (Minus) zeitlich nach der Eingangspipe geöffnet wurde (?)
|
theinlein
Anmeldungsdatum: 29. Dezember 2007
Beiträge: 1279
|
So isses wohl: Wenn man sich die Ausgaben anschaut, dann - wir haben ja schlussendlich insgesamt 4 verschiedene Prozesse laufen - taucht zu jedem 'cnt-Wert' die Ausgabe je 4 mal auf. Das ist so erklärbar, dass jedes Kind ja auch den aktuellen Ausgabepuffer seines Vaters kopiert bekommt - es erbt also die Ausgabezeilen, die der Vater zuvor bereits getätigt hat.
Deshalb kommt jedes printf 4 mal vor.
cnt = 0, fork_pid = 5395, my_pid = 10960
cnt = 0, fork_pid = 5395, my_pid = 10960
cnt = 0, fork_pid = 5395, my_pid = 10960
cnt = 0, fork_pid = 5395, my_pid = 10960
cnt = 1, fork_pid = 10962, my_pid = 10960
cnt = 1, fork_pid = 10962, my_pid = 10960
cnt = 2, fork_pid = 10964, my_pid = 10960
cnt = 1, fork_pid = 0, my_pid = 10962
cnt = 1, fork_pid = 0, my_pid = 10962
cnt = 2, fork_pid = 10963, my_pid = 10962
cnt = 2, fork_pid = 0, my_pid = 10963
cnt = 2, fork_pid = 0, my_pid = 10964 'Das cat -' macht dann wohl mit dem Minus ein Re-Open und lässt zu jedem Prozess der an der momentanen Eingabe hängt (die Ausgabe wurde ja durch die Pipe umgelenkt auf das 'cat') den ganzen Puffer noch mal rein.
|
Vain
Anmeldungsdatum: 12. April 2008
Beiträge: 2510
|
theinlein schrieb: Das ist so erklärbar, dass jedes Kind ja auch den aktuellen Ausgabepuffer seines Vaters kopiert bekommt - es erbt also die Ausgabezeilen, die der Vater zuvor bereits getätigt hat.
Das ja, aber an die Sache mit dem „cat - “ und „Re-open“ glaube ich nicht. Folgendes Minimalbeispiel:
| #include <stdio.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
printf("Hi.");
fork();
printf("\n");
return 0;
}
|
Das gibt zweimal „Hi.“ aus bei einem normalen Aufruf. Aber auch, wenn man ein „cat - “ dahinterstellt. Ich schätze, der Knackpunkt ist, dass die Ausgabe an ein Terminal anders abläuft als die in eine Pipe. Bei einer Pipe wird anders gepuffert (wie im Detail weiß ich jetzt auch nicht, aber auf jeden Fall nicht zeilenweise wie bei einem Terminal). Wenn man nun hergeht und diesen zusätzlichen Puffer abschaltet, dann stimmt auch die Ausgabe mit einer Pipe:
$ stdbuf -o0 ./lordbentest | stdbuf -i0 cat
cnt = 0, fork_pid = 11441, my_pid = 13018
cnt = 1, fork_pid = 13020, my_pid = 13018
cnt = 2, fork_pid = 13021, my_pid = 13018
cnt = 2, fork_pid = 0, my_pid = 13021
cnt = 1, fork_pid = 0, my_pid = 13020
cnt = 2, fork_pid = 13022, my_pid = 13020
cnt = 2, fork_pid = 0, my_pid = 13022 (Ob ihr das Tool „stdbuf “ habt, hängt davon ab, ob ihr schon die GNU coreutils mit mindestens Version 7.5 habt.) „cat - “ und „cat “ ist übrigens dasselbe und kopiert einfach nur STDIN nach STDOUT.
|
theinlein
Anmeldungsdatum: 29. Dezember 2007
Beiträge: 1279
|
Hi Vain, hab noch keine ganze Erklärung, aber hier mal ein anderes Beispiel, das noch zeigt, dass 'cat' und 'cat -' nicht dasselbe ist: echo Hallo | cat datei
liefert den Dateiinhalt von datei OHNE das 'hallo' vom echo !! echo Hallo | cat - datei liefert erst das hallo, dann den Dateiinhalt. Irgendwie passiert da ein erneutes Öffnen des stdin. Sobald cat Argumente in der Commandline hat (Eingangsdateien) ignoriert er die Pipe und macht explizit ein open auf stdin.
|
track
Anmeldungsdatum: 26. Juni 2008
Beiträge: 7174
Wohnort: Wolfen (S-A)
|
Nee falsch. Sobald cat Argumente hat, arbeitet er die ab anstelle von stdin. (soweit ok und klar ..) Und wenn er mehrere Argumente hat, zieht er alle Dateien, die er gereicht bekommt, zu einer Ausgabe zusammen. Nun steht aber das Argument "-" für "/dev/stdin" ... also zieht er stdin (hier also die Pipe) und die Datei zu einer Ausgabe zusammen. Ganz normal. Genau das steht übrigens auch als Beispiel in man cat ... C'est tout. LG, track
|
theinlein
Anmeldungsdatum: 29. Dezember 2007
Beiträge: 1279
|
@ track, hab ich doch gemeint:
nacheinander werden die in der Commandline genannten Files geöffnet und ausgegeben.
|
theinlein
Anmeldungsdatum: 29. Dezember 2007
Beiträge: 1279
|
Es wird immer merkwürdiger ... auf meinem alten Notebook mit SuSe 10.2 (das ist gut 4 Jahre her) gibt es den Unterschied zwischen
program | cat
und
program | cat - so nicht. Ohne cat 7 zeilen, mit cat 12 Zeilen.
|