Comment il fonctionne, c'est largement hors de propos - en tant que développeur de travail à un certain niveau (c'est à dire, le codage de l'Api UNIX), vous avez vraiment besoin de savoir qui il travaille.
Cela dit cependant, et en reconnaissant que la curiosité ou le besoin de comprendre en profondeur est généralement une bonne qualité à avoir, il ya un certain nombre de façons que cela peut être fait.
Tout d'abord, votre affirmation selon laquelle une fonction ne peut retourner qu'une seule valeur est correcte aussi loin qu'il s'en va, mais vous devez vous rappeler que, après le processus de scission, il y a en fait deux instances de la fonction en cours d'exécution, un dans chaque processus. Ils sont le plus souvent indépendants les uns des autres et peuvent suivre différents chemins de code. Le diagramme suivant peut aider dans la compréhension de ce:
Process 314159 | Process 271828
-------------- | --------------
runs for a bit |
calls fork |
| comes into existence
returns 271828 | returns 0
Vous pouvez espérer y voir qu'une seule instance d' fork
ne peut retourner qu'une seule valeur (comme toute autre fonction C) mais il y a en fait plusieurs instances en cours d'exécution, qui est pourquoi il est dit de retourner plusieurs valeurs dans la documentation.
Voici une possibilité sur la façon dont il pourrait travailler.
Lorsque l' fork()
fonction commence à courir, il stocke le courant ID de processus (PID).
Puis, quand vient le temps de retour, si le PID est le même que celui stocké, c'est le parent. Sinon, c'est l'enfant. Le Pseudo-code suivant:
def fork():
saved_pid = getpid()
# Magic here, returns PID of other process or -1 on failure.
other_pid = split_proc_into_two();
if other_pid == -1: # fork failed -> return -1
return -1
if saved_pid == getpid(): # pid same, parent -> return child PID
return other_pid
return 0 # pid changed, child, return zero
Notez qu'il y a beaucoup de magie dans l' split_proc_into_two()
appel et il est presque certainement ne fonctionne pas de cette façon à tous sous les couvertures(un). C'est juste pour illustrer les concepts autour de lui, qui est en gros:
- d'obtenir l'original PID avant la scission, qui restera la même pour les deux procédés, après leur séparation.
- faire la distinction.
- obtenir le PID après la scission, ce qui sera différent dans les deux processus.
Vous pouvez également prendre un coup d'oeil à cette réponse, il explique l' fork/exec
philosophie.
(a) Il est presque certainement plus complexe que ce que j'ai expliqué. Par exemple, dans MINIX, l'appel à l' fork
finit par courir dans le noyau, qui a accès à l'ensemble de l'arborescence des processus.
Il copie simplement le processus parent structure dans un slot libre pour l'enfant, le long des lignes de:
sptr = (char *) proc_addr (k1); // parent pointer
chld = (char *) proc_addr (k2); // child pointer
dptr = chld;
bytes = sizeof (struct proc); // bytes to copy
while (bytes--) // copy the structure
*dptr++ = *sptr++;
Alors il fait de légères modifications à l'enfant de la structure pour s'assurer qu'il sera approprié, y compris la ligne:
chld->p_reg[RET_REG] = 0; // make sure child receives zero
Donc, fondamentalement identique au régime j'ai postulé, mais à l'aide de modifications de données plutôt que le code de sélection de chemin de décider ce qu'il doit retourner à l'appelant - en d'autres termes, vous devriez voir quelque chose comme:
return rpc->p_reg[RET_REG];
à la fin de l' fork()
, de sorte que la valeur correcte revient selon qu'il est le parent ou l'enfant de processus.