Selon Wikipedia (ce qui pourrait être faux)
Lorsqu'un appel système fork () est émis, une copie de toutes les pages correspondant au processus parent est créée, chargée dans un emplacement mémoire séparé par le système d'exploitation pour le processus enfant. Mais cela n'est pas nécessaire dans certains cas. Considérez le cas où un enfant exécute un "
exec
" appel système (qui est utilisé pour exécuter n'importe quel fichier exécutable depuis un programme C) ou se termine très peu de temps aprèsfork()
. Lorsque l'enfant est nécessaire uniquement pour exécuter une commande pour le processus parent, il n'est pas nécessaire de copier les pages du processus parent, carexec
remplace l'espace d'adressage du processus qui l'a invoqué par la commande à exécuter.Dans de tels cas, une technique appelée copie sur écriture (COW) est utilisée. Avec cette technique, lorsqu'un fork se produit, les pages du processus parent ne sont pas copiées pour le processus enfant. Au lieu de cela, les pages sont partagées entre l'enfant et le processus parent. Chaque fois qu'un processus (parent ou enfant) modifie une page, une copie distincte de cette page particulière seule est créée pour ce processus (parent ou enfant) qui a effectué la modification. Ce processus utilisera alors la page nouvellement copiée plutôt que celle partagée dans toutes les références futures. L'autre processus (celui qui n'a pas modifié la page partagée) continue d'utiliser la copie d'origine de la page (qui n'est plus partagée maintenant). Cette technique est appelée copie sur écriture car la page est copiée lorsqu'un processus y écrit.
Il semble que lorsque l'un des processus tente d'écrire sur la page, une nouvelle copie de la page est allouée et affectée au processus qui a généré l'erreur de page. La page d'origine est marquée en écriture par la suite.
Ma question est: que se passe-t-il si le fork()
obtient appelé plusieurs fois avant que l'un des processus ne tente d'écrire sur une page partagée?
pmap -XX PID
oucat /proc/PID/smap
.Réponses:
Rien de particulier ne se produit. Tous les processus partagent le même ensemble de pages et chacun obtient sa propre copie privée lorsqu'il souhaite modifier une page.
la source
Le comportement de fork () varie selon que le système * nix a une MMU ou non. Sur un système non-MMU (comme les premiers PDP-11), l'appel système fork () a copié toute la mémoire du parent pour chaque enfant. Sur un système * nix basé sur MMU, le noyau marque toutes les pages non empilées comme R / O et les partage entre le parent et l'enfant. Ensuite, lorsque l'un des processus écrit sur une page, la MMU intercepte la tentative, le noyau alloue ensuite une page accessible en écriture et met à jour les tables de pages MMU pour pointer vers la page désormais accessible en écriture. Ce comportement de copie sur écriture offre une accélération car initialement, seule une pile privée doit être allouée et clonée pour chaque processus enfant.
Si vous exécutez du code parent entre chaque appel fork (), les processus enfants résultants diffèrent par les pages qui ont été modifiées par le parent. D'un autre côté, si le parent émet simplement plusieurs appels fork (), par exemple dans une boucle, alors les processus enfants seront presque identiques. Si une variable de boucle locale est utilisée, elle sera différente dans la pile de chaque enfant.
la source
Lorsque le système exécute un fork, généralement (cela peut dépendre de l'implémentation), il marque également les pages en lecture seule et marque le processus parent comme maître de ces pages.
Lorsque vous essayez d'écrire sur ces pages, une erreur de page se produit et le système d'exploitation prend le relais, copiant la liste entière des pages ou uniquement les pages modifiées (encore une fois, en fonction de l'implémentation), de sorte que le processus d'écriture aura une copie inscriptible.
Lorsqu'il existe plusieurs processus issus du même, lorsque le processus "maître" écrit dans sa mémoire, les autres processus obtiennent leurs pages équivalentes copiées.
la source