Quelle est la différence entre fork()
y vfork()
? Est-ce que vfork()
retourner comme fork()
.
Réponses
Trop de publicités?L'intention de vfork
était d'éliminer la surcharge de la copie de l'image du processus entier si vous voulez seulement faire une exec*
dans l'enfant. Parce que exec*
remplace l'ensemble de l'image du processus enfant, il est inutile de copier l'image du parent.
if ((pid = vfork()) == 0) {
execl(..., NULL); /* after a successful execl the parent should be resumed */
_exit(127); /* terminate the child in case execl fails */
}
Pour d'autres types d'utilisation, vfork
est dangereux et imprévisible.
Cependant, avec la plupart des noyaux actuels, y compris Linux, le principal avantage de l'option vfork
a disparu à cause de la façon dont fork
est mis en œuvre. Plutôt que de copier l'image entière lorsque fork
est exécuté, des techniques de copie sur écriture sont utilisées.
Comme il a déjà été dit, le vfork
est claire sur les différences. Ce site sujet donne une bonne description de fork
, vfork
, clone
y exec
.
Voici quelques différences souvent négligées entre fork
y vfork
J'en ai fait l'expérience sur certains systèmes embarqués Linux 2.6.3x avec lesquels j'ai travaillé.
Même avec les techniques de copie sur écriture, fork
échoue si vous n'avez pas assez de mémoire pour dupliquer la mémoire utilisée par le processus parent. Par exemple, si le processus parent utilise 2 Go de mémoire résidente (c'est-à-dire de la mémoire qui est utilisée et pas seulement allouée), fork
échoue si vous avez moins de 2 Go de mémoire libre. C'est frustrant lorsque vous voulez juste exec
un programme simple et n'aura donc jamais besoin de cet énorme espace d'adressage parent !
vfork
n'a pas ce problème de mémoire, car il ne duplique pas l'espace d'adresse parent. Le processus enfant agit plus comme un thread dans lequel vous pouvez appeler exec*
o _exit
sans nuire à votre processus parental.
Parce que les tables de pages de mémoire ne sont pas dupliquées, vfork
est beaucoup plus rapide que fork
y vfork
Le temps d'exécution d'un processus n'est pas affecté par la quantité de mémoire utilisée par le processus parent, comme indiqué ici : http://blog.famzah.net/2009/11/20/fork-gets-slower-as-parent-process-use-more-memory/
Dans les situations où les performances sont critiques et/ou la mémoire limitée, vfork
+ exec*
peut donc être une bonne alternative à fork
+ exec*
. Le problème est qu'il est moins sûr et que la page de manuel indique que vfork
est susceptible d'être déprécié à l'avenir.
Une solution plus sûre et plus portable peut consister à examiner la posix_spawn
qui est de niveau supérieur et offre plus d'options. Elle utilise en toute sécurité vfork
lorsque cela est possible, en fonction des options que vous lui passez. J'ai été capable d'utiliser posix_spawn
avec succès et surmonter cet ennuyeux "problème de double vérification de la mémoire" qui fork
+ exec
me donnait.
Une très bonne page sur ce sujet, avec des liens vers d'autres sites. posix_spawn
exemples.
De ma page de manuel
(Extrait de POSIX.1) La fonction vfork() a le même effet que fork(2), sauf que t processus créé par vfork() modifie toute donnée autre qu'une variable de type pid_t utilisée pour enregistrer la valeur de retour de vfork(), ou retourne de l'application fonction dans laquelle vfork() a été appelée, ou appelle toute autre fonction avant d'avoir réussi à appeler _exit(2) ou fonctions.
vfork() diffère de fork(2) par les points suivants que le parent est suspendu jusqu'à ce que le enfant se termine (soit normalement, en appelant _exit(2), ou anormalement, après la délivrance d'un signal fatal), ou qu'il fasse un appel à execve(2). Jusqu'à ce moment, l'enfant enfant partage toute la mémoire avec son parent, y compris la pile. L'enfant ne doit pas retourner de la fonction courante ou appeler exit(3), mais peut appeler _exit(2).
Certains systèmes ont un appel système vfork(), qui a été conçu à l'origine comme une version moins coûteuse de fork(). Puisque fork() impliquait de copier l'espace d'adressage entier du processus, et était donc assez coûteuse, la fonction vfork() a été introduite (dans 3.0BSD).
Cependant, depuis l'introduction de vfork(), l'implémentation de fork() s'est améliorée de façon drastique, plus particulièrement avec l'introduction de `copy-on-write', où la copie de l'espace d'adressage du processus est simulée de façon transparente en permettant aux deux processus de se référer à la même mémoire physique jusqu'à ce que l'un d'entre eux la modifie. Cela supprime en grande partie la justification de vfork() ; en effet, une grande proportion de systèmes n'ont plus du tout la fonctionnalité originale de vfork(). vfork() complètement. Pour des raisons de compatibilité, cependant, il peut toujours y avoir un appel vfork() présent, qui appelle simplement fork() sans essayer d'émuler toute la sémantique de vfork().
Par conséquent, il est très peu judicieux d'utiliser les différences entre fork() et vfork(). En effet, il est probablement peu judicieux d'utiliser vfork() du tout, sauf si vous savez exactement pourquoi vous le voulez.
La différence fondamentale entre les deux 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 étrange des choses continue jusqu'à ce que le processus enfant sorte, ou appelle execve(), à quel point 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 a besoin de sortir, il devrait utiliser _exit() ; en fait, c'est aussi vrai pour l'enfant d'un fork() normal).
- Réponses précédentes
- Plus de réponses