Aller au contenu

Programmes et processus

Que se passe-t-il quand tu lances réellement un programme?

La distinction est fondamentale :

  • Un programme est un fichier exécutable stocké sur le disque. C’est du code inerte : il ne fait rien tant qu’on ne le lance pas.
    Exemples : /usr/bin/ls, /usr/bin/node, /usr/bin/nginx.
  • Un processus est une instance en exécution d’un programme.
    Quand tu tapes node server.js, le fichier programme node est chargé en mémoire et devient un processus vivant, avec son propre espace mémoire, ses variables d’environnement et un numéro d’identification unique.

On peut lancer plusieurs processus à partir du même programme.
Exemple:

  • Trois onglets de navigateur = Trois processus distincts issus du même programme Firefox.
  • Deux serveurs Node.js sur des ports différents = Deux processus à partir du même programme node.

Chaque processus reçoit un PID (Process ID) : un numéro unique attribué par le système au moment de sa création. Ce PID est la façon dont tu identifies et interagis avec un processus spécifique.

Chaque processus connaît aussi le PID de son parent : le processus qui l’a lancé. C’est le PPID (Parent PID). Cette relation parent-enfant crée un arbre de processus dont la racine est systemd (PID 1), le premier processus utilisateur lancé par le noyau lors du démarrage du système.

Fenêtre de terminal
echo $$ # PID du shell courant
echo $PPID # PID du parent de ce shell
pstree -p # Affiche l'arbre de processus avec les PID

La commande ps (process status) affiche un instantané des processus en cours.

Fenêtre de terminal
# Lister tous les processus du système
ps aux
# Décoder les colonnes principales :
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# www-data 1234 0.5 2.1 245000 42000 ? Ss 09:15 0:03 nginx: worker process
# Surveillance en temps réel
top # Vue classique — appuie sur 'q' pour quitter
htop # Vue améliorée avec couleurs et interactions (à installer)

Pour naviguer et filtrer l’ensemble des processus, on utilise en combinaison la commande grep, un outil fondamental qui filtre les lignes d’un texte en ne gardant que celles qui contiennent un motif donné.
La syntaxe commande | grep motif utilise le pipe (|) pour envoyer la sortie d’une commande vers grep, qui ne laisse passer que les lignes correspondantes.

Fenêtre de terminal
# Filtrer pour trouver un processus précis
ps aux | grep node
pgrep -l node # Plus propre : affiche PID et nom

Avant de devenir un processus, un programme passe par plusieurs étapes. Le chemin dépend du type de langage :

flowchart LR
    subgraph Préparation["Préparation (sur disque)"]
        A["Code source<br>(.js, .py, .c)"] --> B{"Langage?"}
        B -->|Compilé<br>C, Rust, Go| C["Compilation"]
        C --> D["Programme exécutable\n(binaire)"]
        B -->|Interprété<br>JS, Python, Bash| E["Interpréteur<br>(node, python, bash)"]
    end
 
    subgraph Exécution["Exécution (en mémoire)"]
        D --> F["Chargement en<br>mémoire par l'OS"]
        E --> F
        F --> G["Nouveau processus<br>(PID attribué)"]
    end

Une fois créé, un processus ne tourne pas en continu sur le CPU. Il alterne entre plusieurs états, orchestré par l’ordonnanceur (scheduler) du système d’exploitation :

stateDiagram-v2
    [*] --> Prêt : fork() + exec()
    Prêt --> EnExécution : L'ordonnanceur<br>lui donne le CPU
    EnExécution --> Prêt : Temps écoulé<br>(préemption)
    EnExécution --> EnAttente : Appel système<br>(fichier, réseau, sleep)
    EnAttente --> Prêt : Données prêtes<br>(I/O terminé)
    EnExécution --> Terminé : exit() ou signal
    Terminé --> Zombie : Parent n'a pas<br>encore lu le code de sortie
    Zombie --> [*] : Parent appelle wait()
 
    state EnExécution {
        [*] --> CPU
        note right of CPU : Le processus<br>utilise le CPU
    }
  1. Prêt (Ready) — Le processus est en mémoire et attend que l’ordonnanceur lui attribue du temps CPU.
  2. En exécution (Running) — Le processus utilise activement le CPU. Sur un processeur à 4 cœurs, au plus 4 processus peuvent être dans cet état simultanément.
  3. En attente (Sleeping/Blocked) — Le processus attend une ressource externe : lecture d’un fichier sur le disque, réponse du réseau, entrée clavier. Il libère le CPU pendant ce temps.
  4. Terminé (Terminated) — Le processus a fini son travail ou a reçu un signal d’arrêt.
  5. Zombie — Le processus est terminé mais son parent n’a pas encore récupéré son code de sortie.
Fenêtre de terminal
# La colonne STAT dans ps aux indique l'état :
# R — Running (en cours d'exécution)
# S — Sleeping (en attente)
# T — Stopped (suspendu)
# Z — Zombie (terminé mais pas encore nettoyé par son parent)

Quand un processus est créé, le système d’exploitation lui attribue un ensemble de ressources matérielles et logicielles. Comprendre lesquelles aide à diagnostiquer les problèmes de performance.

Les ressources matérielles utilisées par un processus Diagramme montrant un processus au centre avec ses composants internes, entouré des quatre ressources matérielles : CPU, RAM, disque et réseau. CPU Exécute le code RAM Stocke en mémoire Disque Fichiers lus / écrits Réseau Connexions TCP / HTTP Processus (PID 1234 — node server.js) Code du programme Instructions à exécuter Variables d'env PATH, PORT, NODE_ENV Pile d'appels Appels de fonctions (stack) Mémoire dynamique (heap) Objets, tableaux, données allouées Descripteurs de fichiers Fichiers ouverts, sockets, stdin/stdout Couleur = ressource principale associée CPU RAM Disque Réseau
RessourceRôle dans le processusCommande pour observer
RAMStocke le code en cours d’exécution, les variables, la pile d’appelsps aux (colonnes %MEM, RSS)
CPUExécute les instructions du programmeps aux (colonne %CPU), top
DisqueFichiers lus et écrits par le processuslsof -p PID (fichiers ouverts)
RéseauConnexions réseau (sockets, ports)ss -tlnp ou netstat -tlnp

Les signaux sont le mécanisme de communication entre processus (ou entre toi et un processus).

SignalNuméroEffet
SIGTERM15Demande polie de terminer — le processus peut se nettoyer avant de quitter
SIGKILL9Arrêt immédiat et inconditionnel — le processus ne peut pas l’intercepter
SIGINT2Interruption — comme appuyer sur Ctrl+C
SIGTSTP20Suspension — met le processus en pause
SIGHUP1Signal de « raccrochage » — souvent utilisé pour recharger la configuration
Fenêtre de terminal
kill 1234 # Envoie SIGTERM au processus 1234 (arrêt propre)
kill -9 1234 # Envoie SIGKILL — arrêt forcé, à utiliser en dernier recours
kill -HUP 1234 # Envoie SIGHUP — recharge la config sans redémarrer
killall node # Envoie SIGTERM à TOUS les processus nommés "node"
pkill -f "server.js" # Tue les processus dont la ligne de commande contient "server.js"

Jusqu’ici, chaque commande que tu lances dans le terminal bloque le prompt jusqu’à ce qu’elle se termine. C’est le comportement par défaut : la commande s’exécute au premier plan (foreground). Mais parfois, tu veux lancer une commande longue et continuer à travailler dans le même terminal.

Lorsqu’une tache s’exécute en premier plan, le terminal est bloqué pendant l’exécution.

Fenêtre de terminal
node server.js
# Tu ne peux plus rien taper ici tant que le serveur tourne

Il faut simplement ajouter & à la fin de la commande

Fenêtre de terminal
node server.js &
# [1] 5678 — le shell affiche le numéro de job [1] et le PID 5678
# Tu peux continuer à utiliser le terminal
Fenêtre de terminal
# 1. Lance un processus au premier plan
node server.js
# 2. Suspends-le avec Ctrl+Z
# [1]+ Stopped node server.js
# 3. Reprends-le en arrière-plan
bg
# [1]+ node server.js &
# 4. Liste les tâches du shell
jobs
# [1]+ Running node server.js &
# 5. Ramène-le au premier plan
fg %1
# node server.js (le terminal est de nouveau bloqué)