Je cherchais à trouver la différence entre ces quatre sur Google et je m'attendais à ce qu'il y ait une énorme quantité d'informations à ce sujet, mais il n'y avait vraiment pas de comparaison solide entre les quatre appels.
Je me suis mis à essayer de compiler une sorte de coup d'œil de base sur les différences entre ces appels système et voici ce que j'ai obtenu. Toutes ces informations sont-elles correctes / manque-t-il quelque chose d'important?
Fork
: L'appel de fork crée essentiellement un doublon du processus actuel, identique à presque tous les niveaux (tout n'est pas copié, par exemple, les limites de ressources dans certaines implémentations mais l'idée est de créer une copie aussi proche que possible).
Le nouveau processus (enfant) obtient un ID de processus différent (PID) et a le PID de l'ancien processus (parent) comme PID parent (PPID). Étant donné que les deux processus exécutent désormais exactement le même code, ils peuvent déterminer lequel par le code de retour de fork - l'enfant obtient 0, le parent obtient le PID de l'enfant. C'est tout, bien sûr, en supposant que l'appel fork fonctionne - sinon, aucun enfant n'est créé et le parent obtient un code d'erreur.
Vfork
: La différence fondamentale entre vfork et fork est que lorsqu'un nouveau processus est créé avec vfork (), le processus parent est temporairement suspendu et le processus enfant peut emprunter l'espace d'adressage du parent. Cet état de choses étrange se poursuit jusqu'à ce que le processus enfant se termine ou appelle execve (), auquel cas le processus parent continue.
Cela signifie que le processus enfant d'un vfork () doit faire attention à ne pas modifier de manière inattendue les variables du processus parent. En particulier, le processus enfant ne doit pas retourner de la fonction contenant l'appel vfork (), et il ne doit pas appeler exit () (s'il doit quitter, il doit utiliser _exit (); en fait, cela est également vrai pour l'enfant d'une fourche normale ()).
Exec :
L'appel exec est un moyen de remplacer fondamentalement l'ensemble du processus en cours par un nouveau programme. Il charge le programme dans l'espace de processus actuel et l'exécute à partir du point d'entrée. exec () remplace le processus actuel par un exécutable pointé par la fonction. Le contrôle ne revient jamais au programme d'origine, sauf en cas d'erreur exec ().
Clone :
Clone, en tant que fork, crée un nouveau processus. Contrairement à fork, ces appels permettent au processus enfant de partager des parties de son contexte d'exécution avec le processus appelant, comme l'espace mémoire, la table des descripteurs de fichiers et la table des gestionnaires de signaux.
Lorsque le processus enfant est créé avec clone, il exécute l'application de fonction fn (arg). (Cela diffère de fork, où l'exécution continue dans l'enfant à partir du point de l'appel de fork d'origine.) L'argument fn est un pointeur sur une fonction qui est appelée par le processus enfant au début de son exécution. L'argument arg est passé à la fonction fn.
Lorsque l'application de fonction fn (arg) revient, le processus enfant se termine. L'entier renvoyé par fn est le code de sortie du processus enfant. Le processus enfant peut également se terminer explicitement en appelant exit (2) ou après avoir reçu un signal fatal.
Formulaire d'information obtenu:
- Différences entre fork et exec
- http://www.allinterview.com/showanswers/59616.html
- http://www.unixguide.net/unix/programming/1.1.2.shtml
- http://linux.about.com/library/cmd/blcmdl2_clone.htm
Merci d'avoir pris le temps de lire ceci ! :)
fork()
, ce qu'il est sous Linux, et probablement tous les BSD) empruntant l'espace d'adressage de son parent. Tout ce qu'il fait, en plus d'appelerexecve()
ou_exit()
, a un grand potentiel pour gâcher le parent. En particulier,exit()
appelle lesatexit()
gestionnaires et autres "finaliseurs", par exemple: il vide les flux stdio. Le retour d'unvfork()
enfant pourrait potentiellement (même mise en garde que précédemment) gâcher la pile des parents.fork
syscall?Réponses:
vfork()
est une optimisation obsolète. Avant une bonne gestionfork()
de la mémoire, il fallait faire une copie complète de la mémoire du parent, donc c'était assez cher. étant donné que dans de nombreux cas, a afork()
été suivi parexec()
, qui supprime la carte mémoire actuelle et en crée une nouvelle, c'était une dépense inutile. De nos jours,fork()
ne copie pas la mémoire; il est simplement défini comme "copier sur écriture", doncfork()
+exec()
est tout aussi efficace quevfork()
+exec()
.clone()
est l'appel système utilisé parfork()
. avec certains paramètres, il crée un nouveau processus, avec d'autres, il crée un thread. la différence entre eux est juste quelles structures de données (espace mémoire, état du processeur, pile, PID, fichiers ouverts, etc.) sont partagées ou non.la source
vfork
évite le besoin de commettre temporairement beaucoup plus de mémoire juste pour que l'on puisse l'exécuterexec
, et c'est encore plus efficace quefork
, même si ce n'est pas presque aussi élevé. Ainsi, on peut éviter d'avoir à surcharger la mémoire juste pour qu'un gros programme puisse générer un processus enfant. Donc, pas seulement une amélioration des performances, mais cela pourrait le rendre possible.exec
.execve()
remplace l'image exécutable actuelle par une autre chargée à partir d'un fichier exécutable.fork()
crée un processus enfant.vfork()
est une version optimisée historique defork()
, destinée à être utilisée quandexecve()
est appelée directement aprèsfork()
. Cela s'est avéré bien fonctionner dans des systèmes non MMU (oùfork()
ils ne peuvent pas fonctionner de manière efficace) et lors defork()
processus avec une énorme mémoire pour exécuter un petit programme (pensez à JavaRuntime.exec()
). POSIX a standardisé leposix_spawn()
pour remplacer ces deux dernières utilisations plus modernes devfork()
.posix_spawn()
fait l'équivalent d'unfork()/execve()
, et permet également de jongler avec fd entre les deux. Il est censé remplacerfork()/execve()
, principalement pour les plates-formes non MMU.pthread_create()
crée un nouveau fil.clone()
est un appel spécifique à Linux, qui peut être utilisé pour implémenter n'importe quoi defork()
àpthread_create()
. Cela donne beaucoup de contrôle. Inspirérfork()
.rfork()
est un appel spécifique au Plan 9. C'est censé être un appel générique, permettant plusieurs degrés de partage, entre les processus complets et les threads.la source
fork()
- crée un nouveau processus enfant, qui est une copie complète du processus parent. Les processus enfant et parent utilisent différents espaces d'adressage virtuels, qui sont initialement remplis par les mêmes pages mémoire. Ensuite, à mesure que les deux processus sont exécutés, les espaces d'adressage virtuels commencent à différer de plus en plus, car le système d'exploitation effectue une copie paresseuse des pages de mémoire qui sont écrites par l'un de ces deux processus et attribue une copie indépendante des pages modifiées de mémoire pour chaque processus. Cette technique est appelée Copy-On-Write (COW).vfork()
- crée un nouveau processus enfant, qui est une copie "rapide" du processus parent. Contrairement à l'appel systèmefork()
, les processus enfant et parent partagent le même espace d'adressage virtuel. REMARQUE! En utilisant le même espace d'adressage virtuel, le parent et l'enfant utilisent la même pile, le pointeur de pile et le pointeur d'instruction, comme dans le cas du classiquefork()
! Pour éviter les interférences indésirables entre le parent et l'enfant, qui utilisent la même pile, l'exécution du processus parent est gelée jusqu'à ce que l'enfant appelleexec()
(créer un nouvel espace d'adressage virtuel et une transition vers une autre pile) ou_exit()
(terminer l'exécution du processus ).vfork()
est l'optimisation dufork()
modèle "fork-and-exec". Il peut être effectué 4 à 5 fois plus rapidement que lefork()
, car contrairement aufork()
(même avec COW gardé à l'esprit), la mise en œuvre de l'vfork()
appel système n'inclut pas la création d'un nouvel espace d'adressage (l'allocation et la mise en place de nouveaux répertoires de pages).clone()
- crée un nouveau processus enfant. Divers paramètres de cet appel système spécifient quelles parties du processus parent doivent être copiées dans le processus enfant et quelles parties seront partagées entre eux. Par conséquent, cet appel système peut être utilisé pour créer toutes sortes d'entités d'exécution, à partir de threads et se terminant par des processus complètement indépendants. En fait, l'clone()
appel système est la base utilisée pour l'implémentationpthread_create()
et toute la famille desfork()
appels système.exec()
- réinitialise toute la mémoire du processus, charge et analyse le binaire exécutable spécifié, met en place une nouvelle pile et passe le contrôle au point d'entrée de l'exécutable chargé. Cet appel système ne renvoie jamais le contrôle à l'appelant et sert au chargement d'un nouveau programme dans le processus déjà existant. Cet appel système et l'appelfork()
système forment ensemble un modèle de gestion de processus UNIX classique appelé "fork-and-exec".la source
vfork
sont si faibles qu'il serait légal de fairevfork
un synonyme defork
(et POSIX.1-2008 supprimevfork
complètement la spécification). S'il vous arrive de tester votre code sur un système qui les synonyme (par exemple, la plupart des BSD post-4.4 en dehors de NetBSD, les noyaux Linux antérieurs à 2.2.0-pré6, etc.), cela peut fonctionner même si vous violez levfork
contrat, puis explosez si vous l'exécutez ailleurs. Certains de ceux qui le simulentfork
(par exemple OpenBSD) garantissent toujours que le parent ne reprendra pas l'exécution jusqu'à ce que l'enfantexec
ou les enfants_exit
. C'est ridiculement non portable.Les fork (), vfork () et clone () appellent tous do_fork () pour faire le vrai travail, mais avec des paramètres différents.
Pour fork, l'enfant et le père ont la table de pages VM indépendante, mais comme l'efficacité, fork ne copiera pas vraiment les pages, il définit simplement toutes les pages inscriptibles en lecture seule pour le processus enfant. Ainsi, lorsque le processus enfant souhaite écrire quelque chose sur cette page, une exception de page se produit et le noyau alloue une nouvelle page clonée à partir de l'ancienne page avec une autorisation d'écriture. Cela s'appelle "copie sur écriture".
Pour vfork, la mémoire virtuelle est exactement celle de l'enfant et du père --- juste à cause de cela, le père et l'enfant ne peuvent pas être éveillés simultanément car ils s'influenceront mutuellement. Ainsi, le père dormira à la fin de "do_fork ()" et se réveillera lorsque l'enfant appellera exit () ou execve (), car il possédera alors une nouvelle table de pages. Voici le code (dans do_fork ()) que le père dort.
Voici le code (en mm_release () appelé par exit () et execve ()) qui réveille le père.
Pour sys_clone (), il est plus flexible puisque vous pouvez y saisir n'importe quel clone_flags. Donc pthread_create () appelle cet appel système avec de nombreux clone_flags:
int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM);
Résumé: les fork (), vfork () et clone () créeront des processus enfants avec différents montages de ressources de partage avec le processus père. Nous pouvons également dire que vfork () et clone () peuvent créer des threads (en fait, ce sont des processus car ils ont un task_struct indépendant) car ils partagent la table de pages VM avec le processus père.
la source
dans fork (), le processus enfant ou parent s'exécutera en fonction de la sélection du processeur. Mais dans vfork (), l'enfant s'exécutera sûrement en premier. après la fin de l'enfant, le parent s'exécutera.
la source
vfork()
peut simplement être implémenté en tant quefork()
.pid
) - le système d'exploitation peut planifier le nouveau processus pour qu'il s'exécute en parallèle si une telle chose a du sens (par exemple plusieurs processeurs). Si, pour une raison quelconque, vous avez besoin que ces processus s'exécutent dans un ordre série particulier, vous avez besoin d'une synchronisation supplémentaire que le forking ne fournit pas; franchement, vous ne voudriez probablement même pas une fourchette en premier lieu.vfork()
, l'enfant court en premier. C'est dans les pages de manuel; l'exécution des parents est suspendue jusqu'à ce que l'enfant décède ou que l'exec
art. Et ninjalj recherche le code source du noyau. Il n'y a aucun moyen d'implémentervfork()
asfork()
car ils transmettent différents arguments audo_fork()
sein du noyau. Vous pouvez cependant implémentervfork
avec leclone
syscall