Concepts du système d'exploitation et APUE disent
Avec vfork (), le processus parent est suspendu et le processus enfant utilise l'espace d'adressage du parent. Étant donné que vfork () n'utilise pas la copie sur écriture, si le processus enfant modifie des pages de l'espace d'adressage du parent, les pages modifiées seront visibles par le parent une fois qu'il reprendra. Par conséquent, vfork () doit être utilisé avec prudence pour garantir que le processus enfant ne modifie pas l'espace d'adressage du parent.
vfork () est destiné à être utilisé lorsque le processus enfant appelle exec () ou exit () immédiatement après sa création.
Comment dois-je comprendre la dernière phrase?
Lorsqu'un processus enfant créé par des vfork()
appels exec()
, ne exec()
modifie pas l'espace d'adressage du processus parent, en chargeant le nouveau programme?
Lorsqu'un processus enfant créé par des vfork()
appels exit()
, ne exit()
modifie pas l'espace d'adressage du processus parent lors de l'arrêt de l'enfant?
J'ai une préférence pour Linux.
Merci.
posix_spawn
. Il est beaucoup plus difficile d'écrire du code correct en utilisantposix_spawn
qu'avec du vieux simplefork
, et si vous essayez, vous risquez de tomber sur le mur de briques en l'absence d'une action de fichier ou d'un attribut qui fait ce que vous devez faire entrefork
etexec
. Et il n'est pas garanti d'avoir une efficacité de type vfork, donc cela ne résout même pas le problème que les gens veulent qu'il résout.posix_spawn
puisse manquer les fonctionnalités que vous souhaitez (vous pouvez résoudre ce problème via un programme d'assistance intermédiaire, écrit en C ou un script shell inline-on-cmdline), toute tentative pour atteindre ce que vous voulez avecvfork
invoque un comportement non défini dangereux. La spécification devfork
ne permet pas d'appeler des fonctions aléatoires pour configurer l'état pour que l'enfant hérite avantexecve
, et les tentatives de le faire peuvent corrompre l'état du parent.posix_spawn
fonctionne à peu près commevfork
dans la plupart des conditions. Ceux où il y a une différence ont tendance à être exactement les cas oùvfork
c'est très dangereux: où il y a des gestionnaires de signaux installés quiposix_spawn
doivent empêcher l'exécution chez l'enfant avant l'exécution.Lorsque vous appelez
vfork()
, un nouveau processus est créé et ce nouveau processus emprunte l'image de processus du processus parent à l'exception de la pile. Le processus enfant reçoit une nouvelle étoile de pile, mais ne permet pasreturn
de la fonction qui a appelévfork()
.Pendant que l'enfant s'exécute, le processus parent est bloqué, car l'enfant a emprunté l'espace d'adressage du parent.
Peu importe ce que vous faites, tout ce qui accède à la pile ne modifie que la pile privée de l'enfant. Cependant, si vous modifiez des données globales, cela modifie les données communes et affecte donc également le parent.
Les choses qui modifient les données globales sont par exemple:
appeler malloc () ou gratuit ()
en utilisant stdio
modification des paramètres du signal
modification des variables qui ne sont pas locales à la fonction qui a appelé
vfork()
....
Une fois que vous appelez
_exit()
(important, ne jamais appelerexit()
), l'enfant est terminé et le contrôle est rendu au parent.Si vous appelez une fonction de la
exec*()
famille, un nouvel espace d'adressage est créé avec un nouveau code de programme, de nouvelles données et une partie de la pile du parent (voir ci-dessous). Une fois que cela est prêt, l'enfant n'emprunte plus l'espace d'adressage à l'enfant, mais utilise un propre espace d'adressage.Le contrôle est rendu au parent, car son espace d'adressage n'est plus utilisé par un autre processus.
Important: sous Linux, il n'y a pas de véritable
vfork()
implémentation. Linux implémente plutôtvfork()
basé sur lefork()
concept Copy on Write introduit par SunOS-4.0 en 1988. Afin de faire croire aux utilisateurs qu'ils utilisentvfork()
, Linux configure simplement les données partagées et suspend le parent pendant que l'enfant n'appelle pas_exit()
ou l'une desexec*()
fonctions.Linux ne bénéficie donc pas du fait qu'un réel
vfork()
n'a pas besoin de mettre en place une description de l'espace d'adressage pour l'enfant dans le noyau. Il en résulte unvfork()
qui n'est pas plus rapide quefork()
. Sur les systèmes qui implémentent un réelvfork()
, il est généralement 3 fois plus rapidefork()
et affecte les performances des shells qui utilisentvfork()
-ksh93
, le récentBourne Shell
et lecsh
.La raison pour laquelle vous ne devriez jamais appeler
exit()
de l'vfork()
enfant ed est qu'ilexit()
vide stdio au cas où il y aurait des données non vidées de la période précédant l'appelvfork()
. Cela pourrait provoquer des résultats étranges.BTW:
posix_spawn()
est implémenté par-dessusvfork()
,vfork()
ne va donc pas être supprimé du système d'exploitation. Il a été mentionné que Linux n'utilise pasvfork()
pourposix_spawn()
.Pour la pile, il y a peu de documentation, voici ce que dit la page de manuel Solaris:
L'implémentation peut donc faire ce qu'elle veut. L'implémentation Solaris utilise la mémoire partagée pour le cadre de pile de l'appel de fonction
vfork()
. Aucune implémentation n'accorde l'accès aux parties plus anciennes de la pile à partir du parent.la source
posix_spawn()
sur Linuxvfork()
. Ils l'implémentent tous les deux par dessus__clone()
.vfork()
juste des appels,clone()
non? C'est littéralement une doublure dans le noyau.vfork
etfork
sur Linux, il fait quelque chose de mal.