Ich habe versucht, fork()
Verhalten zu verstehen . Diesmal in einem for-loop
. Beachten Sie den folgenden Code:
#include <stdio.h>
void main()
{
int i;
for (i=0;i<3;i++)
{
fork();
// This printf statement is for debugging purposes
// getppid(): gets the parent process-id
// getpid(): get child process-id
printf("[%d] [%d] i=%d\n", getppid(), getpid(), i);
}
printf("[%d] [%d] hi\n", getppid(), getpid());
}
Hier ist die Ausgabe:
[6909][6936] i=0
[6909][6936] i=1
[6936][6938] i=1
[6909][6936] i=2
[6909][6936] hi
[6936][6938] i=2
[6936][6938] hi
[6938][6940] i=2
[6938][6940] hi
[1][6937] i=0
[1][6939] i=2
[1][6939] hi
[1][6937] i=1
[6937][6941] i=1
[1][6937] i=2
[1][6937] hi
[6937][6941] i=2
[6937][6941] hi
[6937][6942] i=2
[6937][6942] hi
[1][6943] i=2
[1][6943] hi
Ich bin eine sehr visuelle Person, und so kann ich die Dinge nur durch Diagramme wirklich verstehen. Mein Lehrer sagte, es würde 8 Hi- Statements geben. Ich habe den Code geschrieben und ausgeführt, und tatsächlich gab es 8 Hi- Anweisungen. Aber ich habe es wirklich nicht verstanden. Also habe ich folgendes Diagramm gezeichnet:
Diagramm aktualisiert, um Kommentare wiederzugeben :)
Beobachtungen:
- Der übergeordnete Prozess (main) muss die Schleife dreimal durchlaufen. Dann wird printf aufgerufen
- Bei jeder Iteration der übergeordneten for-Schleife wird ein fork () aufgerufen
- Nach jedem Aufruf von fork () wird i inkrementiert, und so startet jedes Kind eine for-Schleife von i, bevor es inkrementiert wird
- Am Ende jeder for-Schleife wird "hi" gedruckt
Hier sind meine Fragen:
- Ist mein Diagramm korrekt?
- Warum gibt es zwei Instanzen
i=0
in der Ausgabe? - Welcher Wert von
i
wird nach der Gabelung () auf jedes Kind übertragen? Wenn der gleiche Wert von übertrageni
wird, wann hört dann das "Gabeln" auf? - Ist es immer so, dass
2^n - 1
die Anzahl der gegabelten Kinder gezählt werden kann? Also, hiern=3
, was bedeutet2^3 - 1 = 8 - 1 = 7
Kinder, was ist richtig?
i
die PID und die übergeordnete PID nach dem ausdruckenfork()
. Es sollte einfach sein zu verfolgen, was passiertAntworten:
Hier erfahren Sie, wie Sie es verstehen, beginnend mit der
for
Schleife.Schleife beginnt im übergeordneten,
i == 0
Elternteil
fork()
s, Kind erstellen 1.Sie haben jetzt zwei Prozesse. Beide drucken
i=0
.Die Schleife wird jetzt in beiden Prozessen neu gestartet
i == 1
.Eltern und Kind 1
fork()
, Kinder 2 und 3 erstellen.Sie haben jetzt vier Prozesse. Alle vier drucken
i=1
.Die Schleife wird jetzt in allen vier Prozessen neu gestartet
i == 2
.Eltern und Kinder 1 bis 3, alle
fork()
Kinder 4 bis 7.Sie haben jetzt acht Prozesse. Alle acht drucken
i=2
.Die Schleife wird jetzt in allen acht Prozessen neu gestartet
i == 3
.Die Schleife wird in allen acht Prozessen beendet, da dies
i < 3
nicht mehr der Fall ist.Alle acht Prozesse werden gedruckt
hi
.Alle acht Prozesse werden beendet.
Sie werden also
0
zweimal1
gedruckt, viermal2
gedruckt, achtmalhi
gedruckt und achtmal gedruckt.quelle
fork()
dupliziert nur den Prozess und beide machen auf die gleiche Weise weiter. Beide sind gerade von einemfork()
Anruf zurückgekehrt und werden erst wieder anrufen, wenn sie das nächste Mal auf einen Anruf bei stoßenfork()
. Der einzige Unterschied besteht darin, dassfork()
beim Kind 0 und beim Elternteil etwas anderes zurückgegeben wurde. Bei jedem Prozess sind beide nur von a zurückgekehrtfork()
und fahren dann fort.i++
wird nach dem Aufruf von ausgeführtfork
, denn so ist dasfor
Schleife so funktioniert.fork
möglicherweise fehlschlägt.Eine kleine Erklärung zum zweiten:
for (i = 0;i < 3; i++) { fork(); }
ist ähnlich wie:
i = 0; while (i < 3) { fork(); i++; }
So
i
in den gegabelten Prozesse (beide Eltern und Kind) ist der Wert vor dem Zuwachs. Das Inkrement wird jedoch unmittelbar danach ausgeführtfork()
, sodass das Diagramm meiner Meinung nach als korrekt behandelt werden kann.quelle
printf()
nach demfork()
.i
wird0
sowohl im Elternteil als auch im ersten Kind sein, und beide werden diesenprintf()
Aufruf ausführen . Was Sie in Ihrem Diagramm vermissen, ist, dass das erste rote Kind eine haben solltei == 0
, aber diese Box wird es nichtfork()
. Das gleiche gilt für das zweite rote Kind, es sollte einei == 1
Box für das habenprintf()
, aber diese Box wird es auch nichtfork()
.fork()
bereits passiert. Das erste Kind wirdfork()
zum ersten Mal bei der nächsten Iteration der Schleife, wenni == 1
. Aber es wird die erste Iteration der Schleife abschließen, bevor es das tut (weil es in der Mitte dieser Iteration erstellt wurde), also wird esprintf()
diei=0
.Um Ihre Fragen einzeln zu beantworten:
Ja, im Wesentlichen. Es ist auch ein sehr schönes Diagramm.
Das heißt, es ist richtig, wenn Sie die
i=0
Beschriftungen usw. so interpretieren, dass sie sich auf Iterationen mit vollständiger Schleife beziehen. Was das Diagramm jedoch nicht zeigt, ist, dass nach jedemfork()
der Teil der aktuellen Schleifeniteration nach demfork()
Aufruf auch vom gegabelten untergeordneten Prozess ausgeführt wird.Weil du die hast
printf()
nach demfork()
, so ist es sowohl von dem Eltern - Prozess und der gerade abgezweigten Kind Prozess ausgeführt. Wenn Sie dasprintf()
vor dem verschiebenfork()
, wird es nur vom übergeordneten Prozess ausgeführt (da der untergeordnete Prozess noch nicht vorhanden ist).Der Wert von
i
wird von nicht geändertfork()
, sodass der untergeordnete Prozess denselben Wert wie sein übergeordneter Prozess sieht.Die Sache, an die man sich erinnern sollte
fork()
dass es einmal aufgerufen wird, aber zweimal zurückgegeben wird - einmal im übergeordneten Prozess und einmal im neu geklonten untergeordneten Prozess.Betrachten Sie für ein einfacheres Beispiel den folgenden Code:
printf("This will be printed once.\n"); fork(); printf("This will be printed twice.\n"); fork(); printf("This will be printed four times.\n"); fork(); printf("This will be printed eight times.\n");
Der von erstellte untergeordnete Prozess
fork()
ist ein (fast) exakter Klon seines übergeordneten Prozesses. Aus seiner eigenen Sicht "erinnert" er sich daran, sein übergeordneter Prozess zu sein, und erbt den gesamten Status des übergeordneten Prozesses (einschließlich aller Variablenwerte, des Aufrufstapels und des Anweisung wird ausgeführt). Der einzige unmittelbare Unterschied (abgesehen von Systemmetadaten wie der von zurückgegebenen Prozess-IDgetpid()
) ist der Rückgabewert vonfork()
, der im untergeordneten Prozess Null, im übergeordneten Prozess jedoch ungleich Null (tatsächlich die ID des untergeordneten Prozesses) ist.Jeder Prozess, der a ausführt,
fork()
wird zu zwei Prozessen (außer unter ungewöhnlichen Fehlerbedingungen, bei denen einfork()
Fehler auftreten kann). Wenn Eltern und Kind weiterhin denselben Code ausführen (dh sie überprüfen nicht den Rückgabewert vonfork()
oder ihre eigene Prozess-ID und verzweigen darauf basierend auf verschiedene Codepfade), verdoppelt jede nachfolgende Verzweigung die Anzahl der Prozesse. Ja, nach drei Gabeln erhalten Sie insgesamt 2³ = 8 Prozesse.quelle