Linux & Systèmes PDF Gratuit

Cours Processus en PDF (Intermédiaire)

Programmation Système : les processus — éléments essentiels. Un processus correspond à l'exécution d'une image mémoire d'un programme : code exécutable, segments de données, pile (stack) et tas (heap). Il est identifié par un PID et suivi via la table des processus et le Process Control Block (PCB). La maîtrise des appels système POSIX (fork, exec, wait), des états de processus et des politiques d'ordonnancement est cruciale pour le développement et le diagnostic sous Unix/Linux ; ce PDF de 17 pages rassemble these notions pour révision ciblée ou support de cours.

🎯 Objectifs pédagogiques

  • Multiprogrammation et swapping — définitions techniques et conséquences sur la gestion mémoire et le découpage temporel du processeur ; impact sur performance et concurrence.
  • Structure d'un processus et PCB — composants d'un processus (code, données, stack, heap) et éléments du contexte d'exécution (registres, compteur ordinal, piles user/system) ; mécanisme de changement de contexte côté noyau.
  • Création et remplacement d'image : fork et exec — comportement de fork et rôle des variantes de exec pour remplacer une image mémoire ; héritage des descripteurs de fichiers.
  • Attributs et identité — PID, PPID, UID, EUID, GID, EGID : usage pour contrôle d'accès et traçabilité, et interprétation dans ps et top.
  • Synchronisation et ordonnancement — usage de wait, gestion des signaux (kill, Ctrl+C), suspension/résumé (Ctrl+Z, fg/bg) et modification de priorité avec nice. Risques de processus zombies et orphelins et stratégies de collecte via wait ou handlers de signaux.

Cycle de vie et états d'un processus Linux

Le cycle de vie d'un processus décrit ses transitions entre états gérés par le noyau et par l'ordonnanceur. Après création (souvent via fork), un processus entre en état prêt, puis peut être choisi par l'ordonnanceur pour l'exécution. Des événements matériels ou logiciels (I/O, attente de sémaphore) le placent en état bloqué ; au retour de l'événement il redevient prêt. À la terminaison, l'entrée peut rester brièvement sous forme de zombie jusqu'à ce que le parent récupère le statut.

Ordonnancement préemptif vs coopératif

L'ordonnancement préemptif permet au noyau d'interrompre un processus en cours pour attribuer le CPU à un autre (basé sur priorité, quantum, ou événements), ce qui favorise la réactivité et le partage temporel. Dans un modèle coopératif, un processus cède volontairement le CPU, ce qui simplifie le modèle mais peut poser des problèmes si un processus monopolise l'exécution. Les notions d'ordonnanceur, de changement de contexte, d'image mémoire et d'espace d'adressage sont centrales pour comprendre l'impact de ces modèles sur latence et débit.

Les différents états d'un processus

  • Nouveau
  • Prêt (Ready)
  • Élu (Running)
  • Bloqué (Blocked)
  • Terminé (Zombie / Exit)

Processus — structure, espace d'adressage et attribution des ressources

Un processus regroupe l'image mémoire (segment de texte), les segments de données, la pile utilisateur et le tas, ainsi que le contexte d'exécution stocké dans le PCB (registres, pointeur d'instruction, descripteurs de fichiers ouverts). Le mécanisme de changement de contexte sauvegarde et restaure ce PCB pour permettre le multitâche.

Distinction Espace Utilisateur et Espace Noyau

L'espace utilisateur contient l'image mémoire des applications et n'a pas accès directement aux ressources matérielles protégées. L'espace noyau possède les privilèges pour gérer I/O, planification et mémoire physique. Les appels système servent d'interface sécurisée entre ces espaces : l'application passe des arguments (via registres ou pile), le noyau exécute l'opération puis retourne le résultat. Cette séparation protège l'intégrité du système et structure l'attribution des ressources.

Architecture mémoire d'un processus : Stack, Heap et Text

L'architecture mémoire typique d'un processus comprend le segment de texte (code exécutable), les données statiques, la heap (allocation dynamique) et la stack (variables locales et retours d'appel). Le segment de texte est généralement en lecture seule et peut être partagé entre processus exécutant le même binaire. Le heap croît via malloc/brk et nécessite une gestion prudente pour éviter fuites et fragmentation. La connaissance de ces segments est essentielle pour le diagnostic des problèmes mémoire et pour optimiser le changement d'image mémoire lors d'exec.

Exemple pratique de programmation système en C

Extrait minimal illustrant la création d'un fils, l'exécution d'un nouveau programme dans ce fils et la synchronisation côté parent. Conçu pour compilation et test sur une machine Linux avec outils standards.

Exemple de code C : fork

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void) {
    pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        return 1;
    }
    if (pid == 0) {
        /* processus fils */
        printf("Fils PID=%d\n", getpid());
        execlp("ls", "ls", "-l", (char *)NULL);
        _exit(127); /* si exec échoue */
    } else {
        /* processus père */
        int status;
        if (waitpid(pid, &status, 0) < 0) {
            perror("waitpid");
            return 1;
        }
        if (WIFEXITED(status)) {
            printf("Fils terminé, code=%d\n", WEXITSTATUS(status));
        }
    }
    return 0;
}

Comparaison API Win32 vs Appels Système UNIX

Les API Win32 exposent une couche riche et orientée objets pour la gestion de processus et de threads, avec des primitives dédiées et des conventions d'handle spécifiques, tandis que les appels système UNIX/POSIX proposent des primitives minimales et composables (fork, exec, wait, pthread) où la combinaison des appels et des bibliothèques forme les fonctionnalités de plus haut niveau. Pour la portabilité, il faut adapter le modèle de création de processus (procès lourd sous Win32 vs fork+exec sous Unix) et prendre en compte les différences d'espace d'adressage, d'héritage des descripteurs et de gestion des signaux.

Généalogie des processus

Les relations PID/PPID déterminent la hiérarchie des processus. Un processus orphelin est adopté par le processus responsable d'initialisation du système : traditionnellement init (PID 1), aujourd'hui souvent remplacé par systemd sur de nombreuses distributions Linux. PID 1 a pour rôle la collecte des zombies et le lancement des services système.

Processus 0 (idle/swapper) est une entité du noyau utilisée lors de l'ordonnancement pour représenter l'activité lorsque aucun thread exécutable n'est disponible ; il n'est pas un processus utilisateur et sert principalement aux mécanismes internes du scheduler.

📑 Sommaire du document

Remarque : la présence et le format des exercices corrigés sont à vérifier dans le PDF ; le résumé indique la présence d'exemples et d'exercices, sans préciser systématiquement les corrigés.

💡 Pourquoi choisir ce cours ?

Document concis (17 pages) rédigé par Thierry VAIRA et utilisé dans le cadre pédagogique LT La Salle Avignon – BTS IRIS. Approche pragmatique : contraste API Win32 / appels système Unix, rappel des primitives POSIX (fork, exec, wait) et diagramme d'états pour visualiser la préemption et l'ordonnancement. Le support met l'accent sur les attributs des processus et les commandes système utiles pour le diagnostic.

👤 Public cible et prérequis

  • Public cible : étudiants en BTS/Licence technique, développeurs systèmes ou administrateurs débutants souhaitant consolider les concepts fondamentaux de gestion des processus sous Unix/Linux.
  • Prérequis : connaissances de base en programmation (notamment en C et appels système), familiarité avec la ligne de commande Unix (ps, top, shell) et notions élémentaires de systèmes d'exploitation (fichiers, permissions, processus).

❓ Foire Aux Questions (FAQ)

Quelle est la différence fonctionnelle entre fork() et exec() ?

fork() crée un nouveau processus fils en dupliquant l'image mémoire du parent. Après fork, deux processus distincts continuent l'exécution. exec remplace l'image mémoire du processus courant par un nouveau programme : le PID reste le même mais l'espace d'adressage change.

Comment wait() évite-t-il les problèmes de synchronisation entre parent et fils ?

wait() suspend le processus appelant jusqu'à la terminaison d'un de ses fils et permet de récupérer son statut de sortie, évitant ainsi l'accumulation de processus zombies. Associé à des handlers de signaux ou à waitpid, il facilite la coordination des terminaisons et la gestion correcte des PID/PPID.