J'ai essayé de comprendre fork()
comportement. Cette fois dans un for-loop
. Observez le code suivant:
#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());
}
Voici la sortie:
[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
Je suis une personne très visuelle et la seule façon pour moi de vraiment comprendre les choses est de faire des diagrammes. Mon instructeur a dit qu'il y aurait 8 énoncés salut. J'ai écrit et couru le code, et en effet il y avait 8 déclarations salut. Mais je ne l’ai vraiment pas compris. J'ai donc dessiné le schéma suivant:
Le schéma a été mis à jour pour refléter les commentaires:)
i=0
dans la sortie? i
est reportée sur chaque enfant après le fork ()? Si la même valeur de i
est reportée, à quel moment le "forking" s'arrête-t-il?2^n - 1
serait un moyen de compter le nombre d’enfants qui sont fourchés? Alors, ici n=3
, ce qui signifie 2^3 - 1 = 8 - 1 = 7
enfants, qui est correct?Voici comment le comprendre, en commençant par la boucle for
.
La boucle commence dans le parent, i == 0
Parent fork()
s, création de l'enfant 1.
Vous avez maintenant deux processus. Les deux affichent i=0
.
La boucle redémarre dans les deux processus, maintenant i == 1
.
Parent et enfant 1 fork()
, créant les enfants 2 et 3.
Vous avez maintenant quatre processus. Tous les quatre affichent i=1
.
La boucle redémarre dans les quatre processus, maintenant i == 2
.
Le parent et les enfants 1 à 3 tous fork()
, créant les enfants de 4 à 7 ans.
Vous avez maintenant huit processus. Tous les huit affichent i=2
.
La boucle redémarre dans les huit processus, maintenant i == 3
.
La boucle se termine dans les huit processus, car i < 3
N'est plus vrai.
Les huit processus affichent tous hi
.
Les huit processus se terminent tous.
Ainsi, vous obtenez 0
Imprimé deux fois, 1
Imprimé quatre fois, 2
Imprimé 8 fois et hi
imprimé 8 fois.
i++
Est exécuté après l'appel de fork
, car c'est ainsi que fonctionne la boucle for
.fork
peut échouer.Une petite explication sur le second:
for (i = 0;i < 3; i++)
{
fork();
}
est similaire à:
i = 0;
while (i < 3)
{
fork();
i++;
}
Donc, i
dans les processus forkés (parent et enfant) est la valeur avant incrément. Cependant, l'incrément est exécuté immédiatement après fork()
, donc, à mon avis, le diagramme pourrait être considéré comme correct.
Pour répondre à vos questions une à une:
Mon diagramme est-il correct?
Oui, essentiellement. C'est aussi un très beau diagramme.
C'est-à-dire qu'il est correct si vous interprétez les étiquettes i=0
Etc. comme faisant référence à des itérations de boucle complète. Ce que le diagramme ne montre pas montre cependant, c'est qu'après chaque fork()
, la partie de l'itération de la boucle en cours après l'appel fork()
est également exécutée par le processus fils forké.
Pourquoi y a-t-il deux instances de
i=0
Dans la sortie?
Comme vous avez le printf()
après le fork()
, il est donc exécuté à la fois par le processus parent et par le processus enfant qui vient d'être créé. Si vous déplacez la printf()
avant la fork()
, elle ne sera exécutée que par le parent (car le processus enfant n'existe pas encore).
Quelle valeur de
i
est reportée sur chaque enfant après lafork()
? Si la même valeur dei
est reportée, à quel moment le "forking" s'arrête-t-il?
La valeur de i
n'est pas modifiée par fork()
; le processus enfant voit donc la même valeur que son parent.
La chose à retenir à propos de fork()
est qu'il s'appelle une fois, mais qu'il retourne deux fois - une fois dans le processus parent et une fois dans le processus enfant récemment cloné.
Pour un exemple plus simple, considérons le code suivant:
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");
Le processus enfant créé par fork()
est un clone (presque) exact de son parent. Ainsi, de son propre point de vue, il "se souvient" en étant son parent, héritant de tout l'état du processus parent (y compris toutes les variables). valeurs, la pile d'appels et l'instruction en cours d'exécution). La seule différence immédiate (autre que les métadonnées système telles que l'ID de processus renvoyé par getpid()
) est la valeur renvoyée par fork()
, qui sera égale à zéro dans le processus enfant mais non nulle ( en fait, l’ID du processus enfant) dans le parent.
Est-il toujours vrai que
2^n - 1
Serait un moyen de compter le nombre d'enfants fourchus? Donc, icin=3
, Qui signifie2^3 - 1 = 8 - 1 = 7
Enfants, lequel est correct?
Chaque processus qui exécute une fork()
se transforme en deux processus (sauf dans des conditions d'erreur inhabituelles, où fork()
peut échouer). Si le parent et l'enfant continuent à exécuter le même code (c'est-à-dire qu'ils ne vérifient pas la valeur de retour de fork()
, ni leur propre ID de processus, et qu'ils se connectent à des chemins de code différents en fonction de celui-ci), chaque branche suivante doublera le nombre de processus. Donc, oui, après trois fourchettes, vous obtiendrez 2³ = 8 processus au total.