Créer des processus
Introduction
La fonction fork() permet de créer des processus, mais elle est souvent délaissée au profit des pthreads. Pourtant, il existe des différences significatives entre ces deux méthodes. Prendre le temps de choisir la plus efficace pour créer des traitements parallèles peut être déterminant pour la réussite de votre projet.
fork() vs <pthread>
Processus avec fork()
- Création de processus :
-
La fonction
fork()crée un nouveau processus enfant en dupliquant le processus parent. Le processus enfant a son propre espace mémoire séparé. -
Mémoire :
-
Le processus enfant a une copie séparée de l'espace mémoire du processus parent. Les modifications apportées par l'enfant à son espace mémoire n'affectent pas le parent et vice versa (Copie sur écriture).
-
Contexte :
-
Les processus enfants ont leurs propres contextes d'exécution, piles, etc. Ils ne partagent rien directement avec le processus parent en dehors des ressources système comme les descripteurs de fichiers.
-
Communication :
-
La communication entre processus (
IPC) peut être complexe et nécessite des mécanismes tels que les tubes (pipes), les files de messages, les mémoires partagées ou les sockets. -
Isolation :
- Les processus sont complètement isolés les uns des autres, ce qui renforce la stabilité et la sécurité, mais peut entraîner des surcoûts en termes de performance et de mémoire.
Fonctionnement de fork()
Pour en comprendre le fonctionnement rien de tel qu'un petit exemple.
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
return 1;
} else if (pid == 0) {
printf("Hello from child process! PID: %d\n", getpid());
} else {
printf("Hello from parent process! PID: %d\n", getpid());
}
return 0;
}
Explications :
1) Création du processus :
- En cas d'Erreur: La fonction
fork()crée un nouveau processus. Sifork()échoue, elle renvoie une valeur négative (pid < 0). - Dans le processus enfant:
fork()renvoie0(pid == 0). - Dans le processus parent:
fork()renvoie le PID du processus enfant.
2) Distinction entre parent et enfant :
- Grâce à la valeur retournée par
fork(), nous pouvons distinguer le code exécuté par le processus parent et celui exécuté par le processus enfant.
3) Identifiants de processus :
getpid()retourne l'identifiant du processus courant, ce qui permet de visualiser les différents PIDs pour le parent et l'enfant.
Threads avec pthread
-
Création de threads :
- La bibliothèque
pthreadpermet de créer des threads au sein du même processus. Les threads partagent le même espace mémoire global.
- La bibliothèque
-
Mémoire :
- Tous les threads d'un processus partagent le même espace mémoire global. Ils peuvent accéder et modifier les mêmes variables et structures de données.
-
Contexte :
- Les threads partagent le même contexte d'exécution, mais ont leurs propres piles individuelles pour la gestion des appels de fonctions.
-
Communication :
- La communication entre threads est simplifiée puisque tous les threads partagent le même espace mémoire. Cependant, cela nécessite une gestion prudente des accès concurrents avec des mécanismes de synchronisation (comme les mutex, les sémaphores, etc.).
-
Isolation :
- Les threads ne sont pas isolés les uns des autres. Un thread peut directement affecter le comportement des autres threads en accédant et modifiant les mêmes données, ce qui peut mener à des conditions de concurrence s'il n'y a pas une synchronisation adéquate.
Comparatif
| Caractéristique | fork() (Processus) |
pthread (Threads) |
|---|---|---|
| Espace mémoire | Séparé | Partagé |
| Contextes | Séparés | Partagés (avec piles individuelles) |
| Communication | Mécanismes IPC nécessaires | Mémoire partagée, communication simple |
| Isolation | Complète | Partielle, nécessite une synchronisation |
| Création | Relativement coûteuse en termes de ressources | Plus légère et rapide |
Conclusion
En résumé, l'utilisation de fork() est appropriée lorsque vous avez besoin d'une isolation complète entre les processus, tandis que pthread est plus adapté lorsque vous avez besoin de partager des données et de communiquer facilement entre plusieurs tâches exécutées en parallèle. Le choix entre ces deux dépendra des besoins spécifiques de votre application en termes de performance, de sécurité et de complexité.