Contrôle des processus et remplacement sous Linux

Création de processus avec fork

Sous Linux, la fonction fork génère un nouveau processus à partir d'un processus existant. Le processus original devient le parent, tandis que le nouveau est l'enfant. Lorsque fork est invoqué, le noyau exécute les opérations suivantes :

  • Allocation de structures de données et blocs mémoire spécifiques pour l'enfant.
  • Copie partielle des métadonnées du parenet vers l'enfant.
  • Ajout du processus enfant à la liste système des processus.
  • Retour de fork et activation du planificateur.

Après l'exécution de fork, deux processus partagent le même code binaire et s'exécutent au même point, mais chacun poursuit son propre flux d'instructions. Leur ordre d'exécution dépend du planificateur.

Exemple de code modifié :

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    pid_t id_proc;
    printf("Précédent : PID = %d\n", getpid());
    id_proc = fork();
    if (id_proc == -1) {
        perror("Échec de fork()");
        exit(EXIT_FAILURE);
    }
    printf("Suivant : PID = %d, fork a retourné %d\n", getpid(), id_proc);
    sleep(1);
    return EXIT_SUCCESS;
}

La sortie de ce programme affiche un message initial, puis deux messages supplémentaires : un du processus parent et un de l'enfant. L'enfant n'affiche pas le message initial car il démarre après l'appel à fork.

Copie à l'écriture

Par défaut, les processus parent et enfant partagent les segments de code et de données. Tant qu'aucune modification n'est effectuée, la mémoire est partagée ; lorsqu'un processus tente d'écrire, une copie séparée est créée via le mécanisme de copie à l'écriture. Ce fonctionnement repose sur la détection d'écritures sur des zones mémoire marquées en lecture seule, ce qui déclenche une copie automatique.

Cette technique permet une séparation complète des processus tout en optimisant l'utilisation de la mémoire, car les allocations sont différées jusqu'au besoin réel.

Utilisations courantes de fork

fork est employé pour permettre à un processus parent de se dupliquer et d'exécuter des traitements distincts. Par exemple, un serveur peut utiliser fork pour gérer des requêtes clients en parallèle. De plus, après un appel à fork, le processus enfant peut charger un nouveau programme via des fonctions comme exec.

Raisons d'échec de fork

Les appels à fork peuvent échouer si le système atteint la limite du nombre de processus autorisés ou si l'utilisateur a dépassé son quota de processus.

Terminaison de processus

La terminaison d'un processus consiste à libérer ses ressources, notamment les structures du noyau, la mémoire et les segments de code. Les scénarios incluent :

  • Exécution réussie avec le code de sortie approprié.
  • Exécution terminée mais avec un code d'erreur.
  • Arrêt anormal dû à un signal ou une exception.

Le code de sortie, généralement renvoyé par la fonction main, indique l'état de l'exécution.

Codes de sortie sous Linux

Les codes de sortie permettent de diagnostiquer le résultat d'une commande. La convention est la suivante :

  • 0 : succès.
  • 1 : erreur générale, comme une opération non autorisée ou une division par zéro.
  • 128 + n : terminaison par le signal n, par exemple 130 pour SIGINT (Ctrl+C).

Pour obtenir la description d'un code, on peut utiliser la fonction strerror. Pour consulter le dernier code de sortie dans le shell, on exécute :

echo $?

Ce code est stocké dans la structure task_struct du processus.

Fonctions exit et _exit

Les fonctions exit et _exit servent à terminer un processus, mais diffèrent dans leur comportement. exit effectue un nettoyage des ressources (comme la fermeture des fichiers et l'exécution des fonctions enregistrées avec atexit), tandis que _exit termine immédiatement le processus sans ces étapes.

Étiquettes: Linux processus fork copie-écriture exit

Publié le 29 mai à 08h49