Visuell, was mit fork() in einer For-Schleife passiert

Lesezeit: 8 Minuten

Benutzeravatar von lucidgold
klargold

Ich habe versucht zu verstehen fork() Verhalten. 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 ein sehr visueller Mensch, und daher kann ich die Dinge nur durch Diagramme wirklich verstehen. Mein Lehrer sagte, es wären 8 hallo Aussagen. Ich habe den Code geschrieben und ausgeführt, und tatsächlich gab es 8 hallo Aussagen. Aber ich habe es wirklich nicht verstanden. Also habe ich folgendes Diagramm gezeichnet:

Geben Sie hier die Bildbeschreibung ein

Diagramm aktualisiert, um Kommentare widerzuspiegeln 🙂

Beobachtungen:

  1. Der übergeordnete Prozess (main) muss die Schleife dreimal durchlaufen. Dann wird printf aufgerufen
  2. Bei jeder Iteration der übergeordneten for-Schleife wird eine fork() aufgerufen
  3. Nach jedem Aufruf von fork() wird i inkrementiert, und so startet jedes untergeordnete Element eine for-Schleife von i, bevor es inkrementiert wird
  4. Am Ende jeder for-Schleife wird “hi” ausgegeben

Hier sind meine Fragen:

  • Ist mein Diagramm korrekt?
  • Warum sind da zwei Instanzen von i=0 in der Ausgabe?
  • Welchen Wert von i wird nach dem fork() auf jedes Kind übertragen? Wenn der gleiche Wert von i übertragen wird, wann hört das “forking” dann auf?
  • Ist das immer so 2^n - 1 wäre eine Möglichkeit, die Anzahl der geforkten Kinder zu zählen? Also, hier n=3was bedeutet 2^3 - 1 = 8 - 1 = 7 Kinder, was ist richtig?

  • Warum nicht ausführen und ausdrucken idie PID und die übergeordnete PID nach der fork(). Es sollte einfach sein, zu verfolgen, was passiert

    – Basic

    7. November 2014 um 3:14 Uhr


  • @Basic, das ist das erste, was ich getan habe. Ich habe sogar getpid() und getppid() verwendet und deshalb glaube ich, dass mein Diagramm korrekt ist. Aber ich möchte wirklich, dass jemand dies überprüft.

    – klares Gold

    7. November 2014 um 3:16 Uhr

  • Das ist ein wirklich schönes Diagramm. Hast du es mit dot/graphviz gemacht?

    – Steven Lu

    10. November 2014 um 17:08 Uhr

  • Ich habe Microsoft Visio verwendet. Aber ich benutze jetzt LibreOffice Draw, sehr ähnlich zu Open Office Draw und beide sind Open-Source-Projekte, glaube ich, also kostenlos!

    – klares Gold

    10. November 2014 um 17:15 Uhr

  • Wie haben Sie die Pufferung standardmäßig deaktiviert? Auf der gfg-ide sind die Ausgaben ohne fflush anders – ide.geeksforgeeks.org/0TWiEZund mit bündig – ide.geeksforgeeks.org/0JKaH5

    – Udayraj Deshmukh

    18. September 2017 um 5:21 Uhr

Hier ist, wie man es versteht, beginnend mit dem for Schleife.

  1. Schleife beginnt im Elternteil, i == 0

  2. Elternteil fork()s, Kind 1 erstellen.

  3. Sie haben jetzt zwei Prozesse. Beide drucken i=0.

  4. Loop wird jetzt in beiden Prozessen neu gestartet i == 1.

  5. Eltern und Kind 1 fork()Erstellen der Kinder 2 und 3.

  6. Sie haben jetzt vier Prozesse. Alle vier drucken i=1.

  7. Loop startet jetzt in allen vier Prozessen neu i == 2.

  8. Eltern und Kinder 1 bis 3 alle fork()Erstellen von Kindern 4 bis 7.

  9. Sie haben jetzt acht Prozesse. Alle acht drucken i=2.

  10. Loop startet jetzt in allen acht Prozessen neu i == 3.

  11. Schleife endet in allen acht Prozessen als i < 3 stimmt nicht mehr.

  12. Alle acht Prozesse werden gedruckt hi.

  13. Alle acht Prozesse werden beendet.

Also bekommst du 0 zweimal gedruckt, 1 viermal gedruckt, 2 8 mal gedruckt, und hi 8 mal gedruckt.

  • Super, also stimmt mein Diagramm. Dies erklärt jedoch, warum es zwei Instanzen von i = 0 gibt (weil ich immer den aktuellen Wert von i drucke). Obwohl i=0 übernommen wird, wird der nächste Fork nur ausgeführt, wenn i erhöht wird! Vielen Dank!

    – klares Gold

    7. November 2014 um 4:04 Uhr


  • Ja, fork() dupliziert nur den Prozess und beide gehen auf die gleiche Weise weiter. Beide sind gerade von a zurückgekehrt fork() Anrufund werden keinen weiteren Anruf tätigen, bis sie das nächste Mal auf einen Anruf stoßen fork(). Der einzige Unterschied ist das fork() gab 0 im untergeordneten Element und etwas anderes im übergeordneten Element zurück, aber was jeden Prozess betrifft, so kehrten beide gerade von a zurück fork() und dann weiter.

    – Krähenmann

    7. November 2014 um 4:08 Uhr

  • @PaulGriffiths Nach Ihrer Erklärung wird es ein ausgewogener Baum sein. nicht wahr, aber die Reihenfolge der Ausführung würde variieren, da die Reihenfolge nicht deterministisch, sondern im Wesentlichen ausgewogen ist. Ist es nicht?

    – Nasener

    13. Oktober 2015 um 20:25 Uhr


  • @khan: Meine Erklärung spricht nicht dafür, wann eines dieser Dinge passieren wird, sondern nur, wie oft sie passieren werden. Sie haben Recht, dass die Reihenfolge der Ausführung im Allgemeinen nicht vorhersehbar ist.

    – Krähenmann

    13. Oktober 2015 um 20:38 Uhr

  • @khan: Ich bin mir nicht sicher, wie ich mehr als die Antwort erläutern soll. Zeichne es einfach aus. Beginnen Sie mit einem Knoten und fügen Sie dann dreimal jedem sichtbaren Knoten ein untergeordnetes Element hinzu. Am Ende haben Sie acht Knoten: einen mit drei untergeordneten Knoten, einen mit zwei, zwei mit einem und vier ohne keinen.

    – Krähenmann

    13. Oktober 2015 um 21:09 Uhr

Benutzeravatar von Yu Hao
Yu Hao

  1. Ja das ist richtig. (siehe unten)
  2. Nein, i++ wird ausgeführt nach der Anruf von forkweil das so ist for Schleife funktioniert.
  3. Wenn alles erfolgreich verläuft, ja. Denken Sie jedoch daran fork könnte schief gehen.

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 Prozessen (sowohl Eltern als auch Kind) ist der Wert vor dem Inkrement. Das Inkrement wird jedoch unmittelbar danach ausgeführt fork()also meiner Meinung nach könnte das Diagramm als richtig behandelt werden.

  • Da also i nach dem Aufruf von fork() inkrementiert wird, ist i in einem Kind der letzte Wert von i vom Elternteil? Mein Diagramm ist also NICHT korrekt?

    – klares Gold

    7. November 2014 um 3:22 Uhr

  • @lucidgold Deshalb habe ich dir gesagt, du sollst ein printf einfügen.

    – 2501

    7. November 2014 um 3:22 Uhr

  • @lucidgold Ich denke, dein Diagramm ist richtig, das Forking stoppt, weil i unmittelbar nach dem Aufruf inkrementiert wird. Yu Hao hat es gut erklärt.

    – 2501

    7. November 2014 um 3:35 Uhr


  • @lucidgold: Weil du printf() nach das fork(). i wird sein 0 sowohl im Elternteil als auch im ersten Kind, und beide werden das ausführen printf() Anruf. Was Sie in Ihrem Diagramm vermissen, ist, dass das erste rote Kind eine haben sollte i == 0aber diese Box nicht fork(). Dasselbe gilt für das zweite rote Kind, es sollte eine haben i == 1 Kiste für die printf()aber diese Box nicht fork()entweder.

    – Krähenmann

    7. November 2014 um 3:43 Uhr


  • @lucidgold: Denn wenn das erste Kind geschaffen wird, das erste fork() ist schon passiert. Das erste Kind wird fork() zum ersten Mal bei der nächsten Iteration der Schleife, wenn i == 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 es printf() das i=0.

    – Krähenmann

    7. November 2014 um 3:51 Uhr


Um deine Fragen einzeln zu beantworten:

Ist mein Diagramm korrekt?

Ja, im Wesentlichen. Es ist auch ein sehr schönes Diagramm.

Das heißt, es ist richtig, wenn Sie das interpretieren i=0 usw. Bezeichnungen beziehen sich auf vollständige Schleifeniterationen. Was das Diagramm nicht Show ist jedoch, dass nach jedem fork()der Teil der aktuellen Schleifeniteration nach dem fork() Aufruf wird auch vom gegabelten untergeordneten Prozess ausgeführt.

Warum gibt es zwei Instanzen von i=0 in der Ausgabe?

Denn du hast die printf() nach dem fork(), also wird es sowohl vom übergeordneten Prozess als auch vom gerade gegabelten untergeordneten Prozess ausgeführt. Wenn Sie die verschieben printf() Vor dem fork()wird es nur vom Elternprozess ausgeführt (da der Kindprozess noch nicht existiert).

Welchen Wert von i wird nach dem auf jedes Kind übertragen fork()? Wenn der gleiche Wert von i übertragen wird, wann hört das “forking” dann auf?

Der Wert von i wird nicht verändert durch fork()sodass der untergeordnete Prozess denselben Wert wie sein übergeordneter Prozess sieht.

Die Sache, an die man sich erinnern sollte fork() ist, dass es einmal aufgerufen wird, aber zweimal zurückkehrt – 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 untergeordnete Prozess, der von erstellt wurde fork() ist ein (fast) exakter Klon seines übergeordneten Prozesses und “erinnert” sich daher aus seiner eigenen Sicht daran, sein übergeordneter Prozess zu sein, und erbt den gesamten Status des übergeordneten Prozesses (einschließlich aller Variablenwerte, des Aufrufstapels und der ausgeführten Anweisung). Der einzige unmittelbare Unterschied (abgesehen von Systemmetadaten wie der von zurückgegebenen Prozess-ID getpid()) ist der Rückgabewert von fork()die im untergeordneten Prozess null ist, aber im übergeordneten Prozess ungleich null (eigentlich die ID des untergeordneten Prozesses).

Ist das immer so 2^n - 1 wäre eine Möglichkeit, die Anzahl der geforkten Kinder zu zählen? Also, hier n=3was bedeutet 2^3 - 1 = 8 - 1 = 7 Kinder, was ist richtig?

Jeder Prozess, der a ausführt fork() verwandelt sich in zwei Prozesse (außer unter ungewöhnlichen Fehlerbedingungen, wo fork() könnte daneben gehen). Wenn das Eltern- und das Kind weiterhin denselben Code ausführen (d. h. den Rückgabewert von fork(), oder ihre eigene Prozess-ID, und basierend darauf zu verschiedenen Codepfaden verzweigen), dann verdoppelt jeder nachfolgende Fork die Anzahl der Prozesse. Also, ja, nach drei Forks haben Sie insgesamt 2³ = 8 Prozesse.

  • Ausgezeichnete Antwort. Ich habe mein Diagramm aktualisiert, um Ihre Eingabe widerzuspiegeln. Vielen Dank!

    – klares Gold

    7. November 2014 um 17:10 Uhr

1418990cookie-checkVisuell, was mit fork() in einer For-Schleife passiert

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy