web-dev-qa-db-fra.com

Quelle est la différence entre fork () et vfork ()?

Quelle est la différence entre fork() et vfork() ? vfork() renvoie-t-elle comme fork().

32
user507401

L'intention de vfork était d'éliminer le surcoût de la copie de la totalité de l'image du processus si vous souhaitez uniquement effectuer une exec* chez l'enfant. Car exec* remplace l'image entière 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'utilisations, vfork est dangereux et imprévisible.

Cependant, avec la plupart des noyaux actuels, y compris Linux, le principal avantage de vfork a disparu en raison de la façon dont fork est implémenté. Plutôt que de copier toute l'image lorsque fork est exécuté, des techniques de copie sur écriture sont utilisées.

36

Comme déjà indiqué, la page de manuel vfork indique clairement les différences. Cette rubrique donne une bonne description de fork, vfork, clone et exec.

Voici quelques différences souvent négligées entre fork et vfork que j'ai rencontrées 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 la mémoire utilisée et non seulement allouée), fork échoue s'il vous reste moins de 2 Go de mémoire libre. C'est frustrant quand vous voulez juste exec un programme simple et que vous n'aurez donc jamais besoin de cet immense espace d'adressage parent!

vfork n'a pas ce problème de mémoire, car il ne duplique pas l'espace d'adressage parent. Le processus enfant agit plus comme un thread dans lequel vous pouvez appeler exec* ou _exit sans nuire au processus de vos parents.

Comme les tables de pages mémoire ne sont pas dupliquées, vfork est beaucoup plus rapide que fork et vfork le temps d'exécution de _ 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 la page de manuel indique que vfork est susceptible de devenir obsolète à l'avenir.

Une solution plus sûre et plus portable peut être de regarder le posix_spawn, qui est de niveau supérieur et offre plus d'options. Il utilise en toute sécurité vfork lorsque cela est possible, selon les options que vous lui transmettez. J'ai pu utiliser posix_spawn avec succès et surmonter cet ennuyeux "problème de vérification de la double mémoire" que fork + exec me donnait.

ne très bonne page sur ce sujet, avec des liens vers des posix_spawn exemples.

23
dcoz

Depuis ma page de manuel

(De POSIX.1) La fonction vfork () a le même effet que fork (2), sauf que le comportement n'est pas défini si le processus créé par vfork () modifie soit des données autres qu'une variable de type pid_t utilisée pour stocker le renvoie la valeur de vfork (), ou renvoie de la fonction dans laquelle vfork () a été appelée, ou appelle toute autre fonction avant d'appeler avec succès _exit (2) ou l'une des fonctions de la famille exec (3).

vfork () diffère de fork (2) en ce que le parent est suspendu jusqu'à ce que l'enfant se termine (soit normalement, en appelant _exit (2), soit anormalement, après la livraison d'un signal fatal), ou il passe un appel à execve (2 ). Jusque-là, l'enfant partage toute la mémoire avec son parent, y compris la pile. L'enfant ne doit pas revenir de la fonction actuelle ou appeler exit (3), mais peut appeler _exit (2).

4
SiegeX

Certains systèmes ont un appel système vfork (), qui a été initialement conçu comme une version à faible surcharge de fork (). Puisque fork () impliquait de copier tout l'espace d'adressage du processus, et était donc assez cher, la fonction vfork () a été introduite (dans 3.0BSD).

Cependant, depuis l'introduction de vfork (), l'implémentation de fork () s'est considérablement améliorée, notamment avec l'introduction de "copie sur écriture", où la copie de l'espace d'adressage du processus est truquée de manière transparente en permettant aux deux processus de se référer à la même mémoire physique jusqu'à ce que l'un d'eux le modifie. Cela supprime largement la justification de vfork (); en effet, une grande partie des systèmes n'ont plus complètement les fonctionnalités d'origine de vfork (). Pour des raisons de compatibilité, cependant, il peut toujours y avoir un appel vfork (), qui appelle simplement fork () sans tenter d'émuler toute la sémantique de vfork ().

Par conséquent, il est très imprudent d'utiliser réellement l'une des différences entre fork () et vfork (). En effet, il est probablement imprudent d'utiliser vfork (), sauf si vous savez exactement pourquoi vous le souhaitez.

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 de choses étrange se poursuit jusqu'à ce que le processus enfant se termine ou appelle execve (), auquel moment le processus parent continue.

Cela signifie que le processus enfant d'une vfork () doit faire attention à ne pas modifier de façon 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 ()).

2
cpp-coder

Reportez-vous ici et de wikipedia -

Sur certains systèmes, vfork () est identique à fork (). La fonction vfork () ne diffère de fork () que par le fait que le processus enfant peut partager du code et des données avec le processus appelant (processus parent).

1
Vishal

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 de choses étrange continue jusqu'à ce que le processus enfant se termine ou appelle execve(), point auquel le processus parent continue.

Cela signifie que le processus enfant d'une vfork() doit faire attention à ne pas modifier de façon 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 fork()) normale.

Cependant, depuis l'introduction de vfork(), l'implémentation de fork() s'est considérablement améliorée, notamment avec l'introduction de la "copie sur écriture", où la copie du l'espace d'adressage du processus est truqué de manière transparente en permettant aux deux processus de se référer à la même mémoire physique jusqu'à ce que l'un d'eux le modifie. Cela supprime en grande partie la justification de vfork(); en effet, une grande partie des systèmes n'ont plus fonctionnalité originale de vfork() complètement. Pour des raisons de compatibilité, cependant, il peut toujours y avoir un appel à vfork(), qui appelle simplement fork() sans tenter d'émuler toute la sémantique de vfork().

Par conséquent, il est très imprudent d'utiliser réellement l'une des différences entre fork() et vfork(). En effet, il n'est probablement pas judicieux d'utiliser vfork(), à moins que vous ne sachiez exactement pourquoi vous le souhaitez.

1
Rajesh Pal