Les fonctions fork() et vfork() en C sont toutes deux utilisées pour créer un nouveau processus. Cependant, elles présentent des différences fondamentales dans leur comportement, notamment en ce qui concerne le partage de mémoire et l'ordonnancement des processus.
Comportement de fork()
Lorsqu'on utilise fork(), le système crée un nouveau processus (l'enfant) qui est une copie quasi exacte du processus parent. Cela inclut la copie de l'espace d'adressage (segments de données, de code et de pile) du parent. L'exécution des deux processus se poursuit indépendamment, et l'ordre dans lequel ils s'exécutent n'est pas garanti.
Exemple de fork() (Code et Données)
Considérons un programme simple qui utilise fork() :
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t child_pid;
int counter = 0;
child_pid = fork();
if (child_pid < 0) {
perror("Erreur lors de l'appel à fork");
return 1;
} else if (child_pid == 0) {
// Ce bloc est exécuté par le processus enfant
counter++;
printf("Enfant : PID=%d, counter=%d\n", getpid(), counter);
} else {
// Ce bloc est exécuté par le processus parent
counter++;
printf("Parent : PID=%d, counter=%d\n", getpid(), counter);
}
return 0;
}
Dans cet exemple, la variable counter est incrémentée dans chaque processus après l'appel à fork(). Étant donné que l'enfant reçoit une copie distincte du segment de données du parent, l'incrémentation de counter dans l'enfant n'affcete pas celui du parent, et vice-versa. C'est pourquoi chaque processus affiche counter=1.
Comportement de vfork()
vfork() a été conçu pour optimiser les cas où le processus enfant appelle immédiatement exec() (pour rmeplacer son image par un nouveau programme) ou exit(). Pour ce faire, vfork() partage l'espace d'adressage du parent avec l'enfant. L'enfant s'exécute dans l'espace mémoire du parent, et le parent est suspendu jusqu'à ce que l'enfant appelle _exit() (ou exec()).
Points clés de vfork() :
- Partage de données : L'enfant et le parent partagent le même segment de données. Toute modification apportée par l'enfant aux données est visible par le parent, et vice-versa.
- Ordonnancement : L'enfant est garanti de s'exécuter en premier. Le parent reste bloqué jusqu'à ce que l'enfant termine son exécution via
_exit()ou charge un nouveau programme viaexec(). - Risque de deadlock : Si l'enfant dépend d'une action du parent avant d'appeler
_exit()ouexec(), un interblocage (deadlock) peut survenir car le parent est suspendu. - Utilisation de
_exit(): Il est crucial que l'enfant utilise_exit()(ouexec()) pour terminer. L'utilisation deexit()standard peut entraîner un comportement indéfini carexit()appelle les routines de nettoyage du parent, ce qui peut interférer avec le partage de mémoire.
Exemple de vfork() (Partage de Données)
Modifions le programme précédent pour utiliser vfork() et _exit() :
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main() {
pid_t child_pid;
int counter = 0;
child_pid = vfork();
if (child_pid < 0) {
perror("Erreur lors de l'appel à vfork");
return 1;
} else if (child_pid == 0) {
// Ce bloc est exécuté par le processus enfant
counter++; // Modifie la variable partagée
printf("Enfant : PID=%d, counter=%d\n", getpid(), counter);
_exit(0); // L'enfant termine, libérant le parent
} else {
// Ce bloc est exécuté par le processus parent
// Le parent est bloqué ici jusqu'à ce que l'enfant appelle _exit()
counter++; // Modifie la variable partagée
printf("Parent : PID=%d, counter=%d\n", getpid(), counter);
}
return 0;
}
Dans ce cas, lorsque l'enfant incrémente counter, il modifie la valeur dans l'espace mémoire partagé. Lorsque l'enfant appelle _exit(0), le parent est débloqué et reprend son exécution. Le parent incrémente alors counter, qui a déjà été modifié par l'enfant. Par conséquent, le parent affichera counter=2.
L'utilisation de vfork() peut être plus performante lorsque le processus enfant est destiné à exécuter immédiatement un autre programme via exec(), car elle évite la surcharge coûteuse de la copie de l'espace mémoire. Cependant, elle impose des contraintes strictes sur le comportement de l'enfant et peut introduire des bugs subtils si elle n'est pas utilisée correctement.