1 Vater und 2 Sohnprozesse erzeugen ?
-
Hallo,
ich möchte 1 Vaterprozess erzeugen, der wiederum 2 Sohnprozesse startet:
dieser Code:
pid = fork(); if (pid < 0) { printf("Fehlermeldung: %s bei fork. \n" , strerror(errno)); } else if (pid == 0) { printf("Sohn1: %d \n" , getpid()); } else { printf("Vater: %d: arbeitet weiter... und wartet nicht auf Sohn1: %d\n\n", getpid() , pid); } pid = fork(); if (pid < 0) { printf("Fehlermeldung: %s bei fork. \n" , strerror(errno)); } else if (pid == 0) { printf("Sohn1: %d \n" , getpid()); } else { printf("Vater: %d: arbeitet weiter... und wartet nicht auf Sohn2: %d\n\n", getpid() , pid); }
gibt diese Ausgabe:
http://image-upload.biz/files/8c9d91d6649dc0e3ad0859bc1.png
Ich dachte ich erzeuge hier 2 Sohnprozesse doch sehe ich jede Menge Söhne und Väter... ?
Auch würde ich die Prozesse unter Ubuntu gerne kontrollieren können sprich wer wann startet und beendet wurde etc. Unter der Systemüberwachung sehe ich zwar Prozesse, doch nicht die Prozesse , die von mir erzeugt wurden?
-
Du hast 2 mal fork drin, wodurch die Kinder beim zweiten fork auch zum Vater werden. Du musst dran denken, dass sowohl Vater als auch Sohn den weiteren Code auch ausführen.
-
Badestrand schrieb:
Du hast 2 mal fork drin, wodurch die Kinder beim zweiten fork auch zum Vater werden. Du musst dran denken, dass sowohl Vater als auch Sohn den weiteren Code auch ausführen.
also um einen 2.sohn zu erzeugen vom Vater kann ich ja keinen weiteren Fork() im Sohn aufrufen, das wäre ja der Enkel dann... Nur wie/wo rufe ich das 2. mal fork auf? Vor allem soll der 2. Sohn ja den gleichen Vater haben...hm... also rufe ich ihm Vater Teil fork() nochmals auf? ne kann ja auch net sein. Gibt fork denn immer einen neuen Vater zurück?
-
Pelle schrieb:
also um einen 2.sohn zu erzeugen vom Vater kann ich ja keinen weiteren Fork() im Sohn aufrufen, das wäre ja der Enkel dann... Nur wie/wo rufe ich das 2. mal fork auf? Vor allem soll der 2. Sohn ja den gleichen Vater haben...hm... also rufe ich ihm Vater Teil fork() nochmals auf? ne kann ja auch net sein. Gibt fork denn immer einen neuen Vater zurück?
Bist wohl ein wenig verwirrt?
Also ich kenne fork jedenfalls so (programmiere quasi nie unter Linux), dass es einen Kindprozess abspaltet. Aber du hast doch schon nach dem ersten fork das if-else-Gedings. An der Stelle, die nur vom Vater ausgeführt wird, kannst du doch dann das zweite fork unterbringen.
-
@Pelle: Ändere deinen Code so:
pid = fork(); if (pid < 0) { printf("Fehlermeldung: %s bei fork. \n" , strerror(errno)); } else if (pid == 0) { printf("Sohn1: %d \n" , getpid()); exit(0); /* Kindprozess beenden, sonst ruft er den zweiten fork auf */ } else { printf("Vater: %d: arbeitet weiter... und wartet nicht auf Sohn1: %d\n\n", getpid() , pid); } pid = fork(); if (pid < 0) { printf("Fehlermeldung: %s bei fork. \n" , strerror(errno)); } else if (pid == 0) { printf("Sohn1: %d \n" , getpid()); exit(0); } else { printf("Vater: %d: arbeitet weiter... und wartet nicht auf Sohn2: %d\n\n", getpid() , pid); }
-
supertux schrieb:
@Pelle: Ändere deinen Code so:
pid = fork(); if (pid < 0) { printf("Fehlermeldung: %s bei fork. \n" , strerror(errno)); } else if (pid == 0) { printf("Sohn1: %d \n" , getpid()); exit(0); /* Kindprozess beenden, sonst ruft er den zweiten fork auf */ } else { printf("Vater: %d: arbeitet weiter... und wartet nicht auf Sohn1: %d\n\n", getpid() , pid); } pid = fork(); if (pid < 0) { printf("Fehlermeldung: %s bei fork. \n" , strerror(errno)); } else if (pid == 0) { printf("Sohn1: %d \n" , getpid()); exit(0); } else { printf("Vater: %d: arbeitet weiter... und wartet nicht auf Sohn2: %d\n\n", getpid() , pid); }
ok jetzt werden die 2 Söhne ja gleich nach deren Erstellung beendet, was ja nichts ein soll, d.h. ich müsste vor das exit(0) eine whileschleife einbauen , doch dann würde ja Sohn2 erst erstellt werden, wenn Sohn1 aus der while schleife rausfliegt und sein exit ausführt
Die 2 Sohnprozesse sollen ja parallel laufen und etwas machen können nebenher z.B. Datei öffnen/lesen/beschreiben usw. und erst wenn Sohn1 und Sohn2 mit ihren Aufgaben fertig sind, sollen sie sich beenden.
-
Dann mache doch im Sohn vor exit(0) etwas.
Du scheinst (wie fast alle zu Anfang :D) Schwierigkeiten mit dem Verständnis vom forken zu haben. Fork spaltet den aktuell laufenden Prozess augenblicklick, so dass zwei Prozesse laufen. Diese Prozesse führen aber exakt den gleichen Code aus, so dass Du selbst anhand des Rückgabewertes von fork unterscheiden musst, ob Du den Vater-Teil (nochmal fork) oder den Kind-Teil (Arbeit) durchführst. Nach der Durchführung dieses Teils musst Du aber dafür sorgen, dass zumindest die Kindprozesse irgendwo ordentlich beenden, sonst führen die nämlich selbst nochmal den Code des Vaters aus.
-
pid = fork(); if (pid < 0) { printf("Fehlermeldung: %s bei fork. \n" , strerror(errno)); exit(-1); // auch wichtig! } else if (pid == 0) { printf("Sohn1: %d \n" , getpid()); // hier kann Sohn1 noch etwas machen exit(0); } else { printf("Vater: %d: arbeitet weiter... und wartet nicht auf Sohn1: %d\n\n", getpid() , pid); pid = fork(); // nur der Vater erzeugt einen weiteren Sohn if (pid < 0) { printf("Fehlermeldung: %s bei fork. \n" , strerror(errno)); exit(-1); // auch wichtig! } else if (pid == 0) { printf("Sohn2: %d \n" , getpid()); // hier kann Sohn2 noch etwas machen exit(0); } else { printf("Vater: %d: arbeitet weiter... und wartet nicht auf Sohn2: %d\n\ n", getpid() , pid); } }
Jetzt haben wir zwar 2 Zombie-Prozesse, weil der Vater nicht auf sie wartet, aber zumindest sollten jetzt 2 Kind-Prozesse gestartet sein.
-
wenn ich jetzt z.B. 2 prozesse habe und aber 10 möchte müsste ich ja die while schleife so machen:
was ich net verstehe, warum sehe ich noch nicht mal die prozess Anwendung im prozess manager (Systemüberwachung) von Ubuntu 8.04 ?
#include <sys/types.h> #include <errno.h> main(int argc , int **argv) { pid_t pid; char kdo[50]; int counter; sprintf(kdo,"ps -ef |grep %s |grep defunct |grep -v gep | wc -1" , argv[0]); while(counter <= 4) { pid = fork(); //mit while die ganze logik kapseln if (pid < 0) { printf("Fehlermeldung: %s bei fork. \n" , strerror(errno)); exit(-1); // auch wichtig! } else if (pid == 0) // Sohn erzeugt einen Enkel, insgesamt werden 5 Enkel erzeugt { printf("Sohn1: %d \n" , getpid()); // hier kann Sohn1 noch etwas machen pid = fork(); // nur der Vater erzeugt einen weiteren Sohn if (pid < 0) { printf("Fehlermeldung: %s bei fork. \n" , strerror(errno)); exit(-1); // auch wichtig! } else if (pid == 0) { printf("Sohn2: %d \n" , getpid()); // hier kann Sohn2 noch etwas machen sleep(200); //Enkel2 wartet 200 sekunden exit(0); // hier verabschiedet sich der Enkel } else { printf("Vater: %d: arbeitet weiter... und wartet nicht auf Sohn2: %d\n\ n", getpid() , pid); } sleep(200); //Enkel1 wartet 200 sekunden exit(0); } else { printf("Vater: %d: arbeitet weiter... und wartet nicht auf Sohn1: %d\n\n", getpid() , pid); } counter++; } }
-
also nochmals zur Erklärung:
wenn ich fork() aufrufe bekomme ich eine Kopie des Vaterprozesses(main = Vater?) und einen Sohnprozess zurück = 3 Prozesse richtig? main, vaterprozess und sohnprozess!?
bekomme ich als returncode des forkaufrufes nun 0 , < 0 und > 0 zurück denke schon... oder bekomme ich die pid zurück jedes Prozesses? Habe da unterschiedliche Sachen gelesen, daher verwirrt mich das...
-
Hallo Pelle,
wenn du fork aufrufst bekommst du eine PID zurück.
Die PID hat nun folgende Bedeutung:PID == 0: ich befinde mich hier beim Child PID > 0: ich befinde mich hier beim Vater, fork hat funktioniert. Child hat id PID. PID < 0: ich befinde mich hier beim Vater, fork hat nicht funktioniert. Fehler
Bei PID < 0 ist ein Fehler aufgetreten und kein neuer Prozess wurde angelegt.
In den beiden anderen Fällen wurde ein neuer Prozess angelegt, indem
der aufrufende Prozess kopiert wurde. Der Vater und der Child befinden sich
in der selben Routine (hier bei dir main) nur innerhalb unterschiedlichen
Zweigen deiner If-Anweisung.Eine Zuordnung main = Vater gibt es also nicht. Und für jedes fork() wird nur
ein neuer Prozess gestartet.Warum du in der Prozessanzeige von Ubuntu diese nicht siehst, weiß ich nicht.
Vielleicht daher, weil sie bei dir fast nichts machen.Ruf mal mit "ps -a" alle laufenden Prozesse ab und zähl mal das Vorkommen
deines Executables.Ich hoffe, hiermit konnte ich deine Frage beantworten.
Hier mal ein Beispiel, das es vielleicht noch mehr erklärt:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #define ANZAHL 5 static void child_func() { printf("Sohn: %d\n", getpid()); sleep(5); exit(0); /* wenn child_func abgearbeitet ist, wird der Prozess beended! */ } int main (void) { pid_t children[ANZAHL]; unsigned int i; /* Children erzeugen */ for (i=0; i<ANZAHL; ++i) { pid_t id = fork(); if (id < 0) { printf("(E) bei fork\n"); exit(-1); } else if (id == 0) { /* child */ child_func(); } else { printf("Vater: %d-ter Sohn %d erzeugt\n", i, id); children[i] = id; } } /* Auf children warten */ for (i=0; i<ANZAHL; ++i) { pid_t id; if ((id = waitpid(children[i], NULL, WUNTRACED | WCONTINUED)) > 0) { printf("Vater: child %d terminated\n", id); } else { printf("(E) return id: %d\n", id); } } return 0; }
Bei dem Beispiel habe ich nicht alle möglichen Fehler abgefangen.
Müsste also noch gemacht werden.Gruß mcr
-
danke dir schon mal! habe noch eine Frage:
Warum wird das printf des VAterprozesses nie ausgegeben, wenn doch der Vaterprozess parallel zum Sohnprozess läuft, dürfte der Vater die endlosschleife des Sohnes doch gar nicht beachten?
#include <sys/types.h> #include <errno.h> main(int argc , int **argv) { pid_t pid; char kdo[50]; int status; sprintf(kdo,"ps -ef |grep %s |grep defunct |grep -v gep | wc" , argv[0]); pid = fork(); /*------------------------------------------------ Fehler bei Prozess erzeugen ------------------------------- */ if(pid < 0) { printf("Fehlermeldung %s bei fork. \n", strerror(errno)); exit(-1); } /*------------------------------------------------- Sohn Prozess ---------------------------------------------- */ if (pid == 0) { while(1) { printf("Sohn (%d) kann jetzt ewig arbeiten, da er in einer Schleife läuft! mit 3 sekunden Pause. \n" , getpid()); sleep(3); } } /*-------------------------------------------------- Vater Prozess --------------------------------------------- */ if(pid > 0) { pid = wait(&status); printf("Vater (%d) warte auf Sohn (%d) \n", getpid() , pid); while(1) { printf("Vater (%d): Anzahl an Zombies(toten Kindern): \n", getpid()); system(kdo); sleep(5); // 5 sekunden warten printf("Vater (%d) arbeitet... (Abbruch mit STRG+C) \n" , getpid()); } } }
2. Frage: wenn ich Kinder in deren if-zweig nicht beende mit exit, bestehen diese dann noch nach dem else-zweig des Vaters? Bekomme die prozesse unter ubuntu jetzt angezeigt (erklärung zu kompliziert...) und wenn ich kein exit(0) in den kind-zweig mache verschwindet das Kindlein dennoch aus dem prozessmanager also kann auch keine prozessleiche sein, da es der Vater mit wait(&status); ja abholt bzw. hat er das kindelein überhaupt abgeholt, denn wo kein exit da kein signal an den VAter richtig?
3. warum machst du die funktionen static es geht auch ohne?
4. /* Auf children warten */
for (i=0; i<ANZAHL; ++i) <-- das hier schreibst du NACH dem else-zweig und nicht in den else-zweig. Würde es im else-Zweig stehen würde jeder kind-prozess beendet werden bevor der neue erzeugt wird oder?
-
Pelle schrieb:
danke dir schon mal! habe noch eine Frage:
Warum wird das printf des VAterprozesses nie ausgegeben, wenn doch der Vaterprozess parallel zum Sohnprozess läuft, dürfte der Vater die endlosschleife des Sohnes doch gar nicht beachten?
Das Problem hierbei ist in Zeile 32: Das wait wartet solange, bis ein Sohn
sich beendet hat. Da sich der Sohn nicht beendet, wartet der Vater hier.Ausschnitt aus Man-Page zu wait(): The wait() system call suspends execution of the calling process until one of its children terminates. The call wait(&status) is equivalent to: waitpid(-1, &status, 0);
Pelle schrieb:
2. Frage: wenn ich Kinder in deren if-zweig nicht beende mit exit, bestehen diese dann noch nach dem else-zweig des Vaters? Bekomme die prozesse unter ubuntu jetzt angezeigt (erklärung zu kompliziert...) und wenn ich kein exit(0) in den kind-zweig mache verschwindet das Kindlein dennoch aus dem prozessmanager also kann auch keine prozessleiche sein, da es der Vater mit wait(&status); ja abholt bzw. hat er das kindelein überhaupt abgeholt, denn wo kein exit da kein signal an den VAter richtig?
Ok, dann versuche ich mal auf diese Frage zu antworten:
- Ja, auch wenn der Vater den else-Zweig oder sogar sich selbst beendet hat, laufen die Kindprozesse weiter. - Du musst nicht zwingend exit() benutzen, um einen Child zu beenden. Wenn du in der main()-Funktion des Childs ein return machst, beendet sich der Prozess ebenfalls und der Vater bekommt ein Signal. - Selbst wenn du mit "kill" in der shell ein Kindprozess beendest, bekommt der Vaterprozess das mit.
Gruß mcr
-
Pelle schrieb:
3. warum machst du die funktionen static es geht auch ohne?
4. /* Auf children warten */
for (i=0; i<ANZAHL; ++i) <-- das hier schreibst du NACH dem else-zweig und nicht in den else-zweig. Würde es im else-Zweig stehen würde jeder kind-prozess beendet werden bevor der neue erzeugt wird oder?Zu deinen Fragen:
3. das static gibt an, dass diese Funktion nur innerhalb dieser Datei verwendet werden darf. 4. ja, wenn innerhalb des else-Zweiges ein wait steht, wartet der Prozess solange, bis er etwas bekommen hat. Daher habe ich das Erzeugen und Warten voneinander getrennt.
Gruß mcr
-
natürlich möchte ich mit dem Vater und seinen 10 Söhnen... Töchter? ;P auch was machen. Hier in meinem Buch steht z.B. der VAterprozess soll das Shared Memory initialisieren und die ganzen Söhne soll sich am Shared Memory registrieren mit ihrer PID und deren Startzeit(Zeitpunkt wo sie erzeugt wurden nehme ich an).
"Nach dem ein Shared Memory Segment erzeugt wurde, kann dieses von jedem Prozess an seinen Adressraum gebunden werden, wenn er die Kennung des SHM kennt"!
Ich nehme an mit Vaterprozess SHM initialisieren ist das Erzeugen (shmget) eines SHM-Segements gemeint und mit registrieren der Kindprozesse am SHM ist das Anbinden (shmat) der 10 Prozesse an den erzeugten SHM gemeint ODER ?
Bei dem Beispiel habe ich nicht alle möglichen Fehler abgefangen.
Müsste also noch gemacht werden.Ich kann eigentlich keine möglichen Fehlerquellen sehen, wurde ja immer auf <=> 0 abgefragt bei fork()...??
Nun habe ich eine initSHM() Funktion erstellt um das SHM zu initialisieren bzw. zu erzeugen. Ohne die shmctl() Funktion wird das SHM Segment erstellt, starte ich das Programm ein 2. mal bekomme ich eine Fehlermeldung ala File already exists... ändere ich den SHM_KEY gehts wieder... ok dann lösche ich in der initSHM() Funktion halt jedesmal das SHM Segment das angelegt wurde denke ich mir... doch beim Aufruf von shmctl() bekomme ich die Meldung:
Fehler Identifier Removed beim Loeschen des Shared Memory Segments
Warum das denn? Warum konnte das SHM Segment nicht ordnungsgemäß gelöscht werden?
Edit: ok zuerst müsste man mit shmdt das SHM-Segement abkoppeln, doch im Moment sind keine Prozesse daran gekoppelt mit shmat z.B. daher müsste man ja sofort löschen können, nicht?
Und warum wird beim Erzeugen des SHM Segments "Alles klar..." NIE ausgegeben obwohl es erzeugt wurde? Gibt es keinen iShmId wert über/gleich 0 ?
CodeAuszug:
void initSHM() { int iShmId; iShmId = shmget(SHM_KEY, 100, SHM_W | SHM_R | IPC_CREAT | IPC_EXCL); if(iShmId < 0) { printf("Fehler beim erzeugen einens Shared Memory Segments: %s \n", strerror(errno)); exit(-1); // und tschüss } if(iShmId = 0) printf("Alles klar ist == 0 \n"); if(iShmId > 0) printf("Alles klar ist > 0 \n"); /* Shared Memory Segment abkoppeln/löschen */ if(shmctl(iShmId, IPC_RMID, NULL ) < 0) { printf("Fehler %s beim Loeschen des Shared Memory Segments\n", strerror(errno)); exit(-1); // und tschüss } } int main (void) { pid_t children[ANZAHL_KINDER]; // Hier sind alle PID's der Kinder gespeichert gemäß der Reihenfolge der Erzeugung unsigned int i; printf("Vater hat die PID: %d \n", getpid()); initSHM();
-
Pelle schrieb:
Und warum wird beim Erzeugen des SHM Segments "Alles klar..." NIE ausgegeben obwohl es erzeugt wurde? Gibt es keinen iShmId wert über/gleich 0 ?
Weil du in der if-Anweisung in Zeile 13 eine Zuweisung machst und nicht vergleichst.
Hier fehlt der zweite =.Gruß mcr