Systèmes d'exploitation et processus
Cours complet · NSI (terminale), chapitre 13 · terminale, spécialité numérique et sciences informatiques
Travailler ce chapitre sur Adloun Exercices corrigés de ce chapitre
Entre le matériel d'un ordinateur (processeur, mémoire, disque, périphériques) et les applications que nous utilisons (navigateur, éditeur de texte, interpréteur Python) se trouve une couche logicielle essentielle : le système d'exploitation (en anglais Operating System, abrégé OS). Sans lui, chaque programme devrait connaître les détails du matériel et il serait impossible de faire fonctionner plusieurs applications en même temps sur une seule machine.
Ce chapitre présente le rôle d'un système d'exploitation, la notion de processus et ses différents états, les principes de l'ordonnancement qui permet à un processeur d'exécuter de nombreux programmes simultanément, les problèmes de concurrence entre processus partageant des ressources (dont le redoutable interblocage), puis la gestion des fichiers et des droits. Nous terminerons par une prise en main des commandes de base d'un système, manipulées dans un interpréteur de commandes appelé shell.
13.1 Le rôle d'un système d'exploitation
13.1.1 Une couche d'intermédiaire
Le système d'exploitation est le premier programme lancé au démarrage de la machine (après le micrologiciel d'amorçage). Il reste actif en permanence et sert d'intermédiaire entre les programmes des utilisateurs et le matériel.
Un système d'exploitation est un ensemble de programmes qui gère les ressources matérielles d'un ordinateur (processeur, mémoire, disques, périphériques) et fournit aux applications des services communs au travers d'une interface unifiée. Il assure le partage équitable et sécurisé de ces ressources entre les différents programmes et utilisateurs.
Parmi les systèmes d'exploitation les plus répandus, on trouve la famille Unix (dont Linux, macOS, Android) et Windows. Au cœur du système se trouve le noyau (kernel), qui s'exécute dans un mode privilégié lui donnant un accès direct au matériel.
Un système d'exploitation assure principalement :
- la gestion des processus : création, exécution, arrêt des programmes, et partage du processeur entre eux (ordonnancement) ;
- la gestion de la mémoire : attribution et protection des zones de mémoire, mémoire virtuelle ;
- la gestion des fichiers : organisation des données sur les disques au sein d'un système de fichiers ;
- la gestion des entrées/sorties : communication avec les périphériques via des pilotes (drivers) ;
- la gestion des utilisateurs et des droits : authentification et contrôle des accès.
13.1.2 Le mode protégé et les appels système
Pour garantir la stabilité et la sécurité, le processeur distingue deux modes d'exécution : le mode noyau (privilégié) et le mode utilisateur (restreint). Une application ne peut pas accéder directement au matériel ; elle doit demander un service au noyau au moyen d'un appel système (system call).
Lorsqu'un programme Python exécute open("data.txt").read(), la bibliothèque standard finit par déclencher des appels système (open, read, close). C'est le noyau qui, en mode privilégié, dialogue réellement avec le disque, vérifie les droits d'accès, puis recopie les octets dans la mémoire du programme. L'application n'a jamais eu à connaître le modèle du disque dur.
13.2 Les processus
13.2.1 Programme et processus
Il faut distinguer un programme (un fichier exécutable stocké sur le disque, statique) d'un processus (une exécution de ce programme, en cours, dynamique). Lancer deux fois le même programme crée deux processus distincts.
Un processus est l'instance d'un programme en cours d'exécution. Il est caractérisé par :
- un identifiant unique (le PID, Process IDentifier) ;
- le code à exécuter et la valeur courante du compteur ordinal ;
- un espace mémoire propre (variables, pile, tas) ;
- un état et des ressources ouvertes (fichiers, connexions).
Sur un système Unix, chaque processus possède un processus parent : les processus forment ainsi une arborescence dont la racine est le premier processus lancé par le noyau (souvent appelé init ou systemd).
13.2.2 Les états d'un processus
À un instant donné, un seul processus par cœur de processeur est réellement en train de s'exécuter. Les autres attendent. Le système modélise cette situation par trois états principaux.
Un processus passe au cours de sa vie par trois états fondamentaux :
- prêt (ready) : le processus pourrait s'exécuter, il attend seulement que le processeur lui soit attribué ;
- élu (running) : le processus est en train de s'exécuter sur le processeur ;
- bloqué (blocked, ou en attente) : le processus ne peut pas progresser car il attend un événement extérieur (fin d'une lecture disque, saisie clavier, libération d'une ressource).
Les passages d'un état à l'autre sont les suivants :
- prêt élu : élection. L'ordonnanceur choisit ce processus et lui attribue le processeur.
- élu prêt : préemption (ou fin de quantum). Le système retire le processeur au processus pour le donner à un autre, alors que le processus pourrait encore travailler.
- élu bloqué : le processus demande une ressource non disponible immédiatement (par exemple une entrée/sortie).
- bloqué prêt : réveil. L'événement attendu s'est produit ; le processus redevient candidat à l'élection.
On notera qu'il n'existe pas de transition directe bloqué élu : un processus réveillé repasse d'abord par l'état prêt.
Un programme télécharge un fichier puis l'affiche.
- Il est prêt dès son lancement, en file d'attente.
- L'ordonnanceur l'élit : il devient élu et lance la requête réseau.
- Comme les données réseau n'arrivent pas instantanément, il se bloque en attendant la réponse ; le processeur est rendu à d'autres processus.
- À l'arrivée des données, il est réveillé et redevient prêt.
- Réélu, il redevient élu et affiche le fichier.
13.3 L'ordonnancement
13.3.1 Principe
Sur une machine, il y a presque toujours plus de processus prêts que de cœurs de processeur. L'ordonnanceur (scheduler) est la partie du noyau qui décide, à chaque instant, quel processus prêt obtient le processeur, et pour combien de temps. C'est cette commutation très rapide entre processus qui donne l'illusion du parallélisme sur une machine mono-cœur.
L'ordonnancement est la stratégie selon laquelle le système choisit, parmi les processus à l'état prêt, celui qui passera à l'état élu, et selon laquelle il répartit le temps de processeur entre eux. Le passage d'un processus élu à un autre s'appelle une commutation de contexte (context switch).
On distingue les ordonnancements non préemptifs (un processus élu garde le processeur jusqu'à ce qu'il se bloque ou se termine) et préemptifs (le système peut interrompre un processus élu, typiquement après un quantum de temps, pour donner sa chance à un autre).
- FIFO (First In, First Out, ou Premier arrivé, premier servi) : les processus sont élus dans l'ordre d'arrivée, chacun jusqu'à son terme. Simple mais non préemptif : un long processus pénalise tous les suivants.
- SJF (Shortest Job First) : on élit d'abord le processus dont la durée d'exécution est la plus courte. Minimise le temps d'attente moyen, mais nécessite de connaître les durées.
- Tourniquet (Round Robin) : chaque processus reçoit tour à tour le processeur pour un quantum fixe ; s'il n'a pas fini, il repart en fin de file. Préemptif et équitable.
- Par priorités : à chaque processus est associée une priorité ; le plus prioritaire est élu. Risque de famine pour les processus peu prioritaires.
Méthode : Calculer les temps d'attente et de rotation
Pour analyser une politique d'ordonnancement, on s'appuie sur deux grandeurs :
- le temps de rotation (turnaround) d'un processus instant de fin instant d'arrivée ;
- le temps d'attente temps de rotation durée d'exécution (c'est le temps passé à ne rien faire, à l'état prêt).
On construit un diagramme de Gantt (une frise temporelle indiquant quel processus occupe le processeur à chaque instant), puis on lit les instants de fin pour en déduire les temps demandés. La moyenne de ces temps mesure la qualité de la politique.
13.4 Ressources, concurrence et interblocage
13.4.1 Partage de ressources
Plusieurs processus exécutés simultanément peuvent vouloir utiliser la même ressource : un fichier, une imprimante, une zone de mémoire, une variable partagée. Lorsque l'accès simultané à une ressource peut corrompre les données, on parle de section critique : une portion de code qui ne doit être exécutée que par un seul processus à la fois.
On parle de concurrence lorsque plusieurs processus s'exécutent en se disputant des ressources communes. Pour préserver la cohérence des données, on impose l'exclusion mutuelle : un seul processus à la fois peut accéder à une section critique. On la réalise avec des mécanismes de synchronisation comme les verrous (mutex) ou les sémaphores.
Deux processus incrémentent un compteur partagé valant . Chacun effectue trois étapes : lire la valeur, ajouter , écrire le résultat. Si les exécutions s'entrelacent ainsi :
- P1 lit .
- P2 lit (avant que P1 ait écrit).
- P1 écrit .
- P2 écrit .
Le compteur vaut au lieu de : une incrémentation a été perdue. Ce bug, appelé condition de course (race condition), disparaît si la section critique est protégée par un verrou.
13.4.2 L'interblocage
Les verrous résolvent un problème mais en créent un autre : si des processus attendent mutuellement des ressources que les autres détiennent, plus personne ne peut avancer.
Un interblocage est une situation où un ensemble de processus sont tous bloqués, chacun attendant une ressource détenue par un autre processus du même ensemble. Aucun ne pourra jamais progresser : le système reste figé pour ces processus.
Un interblocage ne peut survenir que si les quatre conditions suivantes sont réunies simultanément :
- exclusion mutuelle : une ressource ne peut être détenue que par un seul processus à la fois ;
- détention et attente : un processus garde ses ressources tout en en demandant de nouvelles ;
- non-préemption : une ressource ne peut être retirée de force à un processus ; il doit la libérer lui-même ;
- attente circulaire : il existe un cycle de processus où chacun attend une ressource détenue par le suivant.
Briser une seule de ces conditions suffit à empêcher tout interblocage.
Deux philosophes partagent deux fourchettes. Chacun a besoin des deux pour manger. Le philosophe A prend la fourchette de gauche, le philosophe B prend la fourchette de droite ; chacun attend alors indéfiniment la fourchette que tient l'autre. C'est un interblocage : attente circulaire entre A et B. Une solution consiste à imposer un ordre global d'acquisition (toujours prendre la fourchette de plus petit numéro d'abord), ce qui brise l'attente circulaire.
13.5 Gestion des fichiers et des droits
13.5.1 Le système de fichiers
Les données persistantes sont organisées en fichiers, eux-mêmes regroupés dans une hiérarchie de répertoires (ou dossiers).
Un système de fichiers est la manière dont un système d'exploitation organise, nomme et stocke les fichiers sur un support. Sous Unix, les fichiers et répertoires forment une arborescence unique dont la racine est notée /. Un chemin absolu part de la racine (par exemple /home/ada/projet.py) ; un chemin relatif part du répertoire courant (par exemple ../images/logo.png).
Deux notations spéciales reviennent souvent : . désigne le répertoire courant et .. désigne le répertoire parent.
13.5.2 Les droits d'accès
Comme un système peut être utilisé par plusieurs personnes, il faut contrôler qui peut lire, modifier ou exécuter chaque fichier. Sous Unix, chaque fichier possède un propriétaire, appartient à un groupe, et porte des droits pour trois catégories : le propriétaire (user), le groupe (group) et les autres (others).
À chaque fichier sont associés trois droits pour chacune des trois catégories d'utilisateurs :
r(read) : droit de lecture ;w(write) : droit d'écriture (modification) ;x(execute) : droit d'exécution (lancer un programme, ou entrer dans un répertoire).
La commande ls -l affiche ces droits sous la forme de neuf caractères, par exemple rwxr-x{-{-}{-}} : rwx pour le propriétaire, r-x pour le groupe, — pour les autres.
Méthode : Convertir des droits en notation octale
On peut représenter les droits d'une catégorie par un chiffre, en additionnant les valeurs des droits présents : On obtient un nombre à trois chiffres (un par catégorie) :
rwx;r-x;rw-;r--.
Ainsi rwxr-x{-{-}{-}} s'écrit 750. La commande chmod 750 script.sh fixe exactement ces droits.
13.6 Commandes de base d'un système
13.6.1 Le shell
L'interpréteur de commandes, ou shell, est un programme qui lit des commandes saisies au clavier (ou dans un script) et les exécute. Il constitue une interface textuelle puissante avec le système.
Le shell est un programme qui interprète les commandes de l'utilisateur et les transmet au système d'exploitation. Il affiche une invite (prompt), attend une commande, l'exécute, puis affiche à nouveau l'invite. Bash est l'un des shells les plus répandus sous Unix.
13.6.2 Navigation et inspection
Les trois commandes fondamentales de navigation :
pwd # affiche le repertoire courant (Print Working Directory)
ls # liste le contenu du repertoire courant
ls -l # liste detaillee : droits, proprietaire, taille, date
ls -a # affiche aussi les fichiers caches (commencant par .)
cd Documents # se deplace dans le sous-repertoire Documents
cd .. # remonte dans le repertoire parent
cd /home/ada # se deplace via un chemin absolu
cd # revient dans le repertoire personnel
mkdir nom: créer un répertoire ;rm fichier: supprimer un fichier (rm -rpour un répertoire et son contenu, à manier avec prudence) ;cp src dst: copier ;mv src dst: déplacer ou renommer ;cat fichier: afficher le contenu d'un fichier ;man commande: afficher le manuel d'une commande.
13.6.3 Modifier les droits avec chmod
La commande chmod (change mode) modifie les droits. On peut utiliser la notation octale ou la notation symbolique :
ls -l rapport.txt # -rw-r--r-- : 644
chmod 600 rapport.txt # notation octale : rw------- (prive)
chmod u+x script.sh # ajoute le droit d'execution au proprietaire
chmod go-w fichier.txt # retire l'ecriture au groupe et aux autres
chmod a+r public.txt # ajoute la lecture a tous (all)
En notation symbolique : u/g/o/a désignent la cible (user, group, others, all), +, -, = l'opération, et r/w/x le droit.