NSI · Première
Architectures et systèmes : processeur, réseau et permissions
Le processeur exécute des instructions en transformant des données ; le système d’exploitation partage les ressources et contrôle les accès. Pour expliquer une machine, suis l’information : où est-elle stockée, quelle instruction agit, quel paquet la transporte, quelle identité peut y accéder et quelle commande en résulte ?
Explications et exemples en accès libre. Ateliers, quiz et cartes avec l’abonnement.
Prévoir mon tempsExplications et exemples en accès libre
Une première étude des explications, schémas, exemples résolus et erreurs expliquées. Les activités, productions, quiz et cartes réservés à l’abonnement ne sont pas comptés ici.
- Comprendre1632 mots d’explication et 4 schémas
- 11 à 19 min
- Étudier les exemples et les erreurs18 cas, exemples et activités guidés
- 36 à 66 min
Étude du cours en accès libre, environ45 min à 1 h 25
Voir le calcul et le temps par étape
Le calcul suit automatiquement les explications et les tâches présentes dans le cours. Ses coefficients sont des repères de planification, pas des temps mesurés auprès d’élèves.
- Lecture active : 1632 mots, à raison de 160 à 220 mots par minute.
- Schémas : 4, avec 1 à 2 min pour lire chacun.
- Exemple guidé : 6 × 2 à 4 min.
- Suivre le code résolu et ses tests : 6 × 3 à 5 min.
- Comprendre une erreur expliquée : 6 × 1 à 2 min.
- Charger, décoder, exécuter : que change chaque instruction ?8 à 15 min
- Des booléens au circuit : comment additionner deux bits ?6 à 13 min
- Paquets et encapsulation : pourquoi découper un message ?7 à 13 min
- Perte et retransmission : comment éviter de livrer deux fois ?8 à 15 min
- Système d'exploitation : chemin, abstraction et droit d'accès8 à 15 min
- Capteur, actionneur, IHM : où placer les garde-fous ?7 à 15 min
Les sous-totaux sont arrondis à la minute, puis additionnés. La fourchette totale est élargie aux cinq minutes voisines. Les étapes ci-dessus comprennent leurs explications et exemples ; elles ne s’ajoutent pas une seconde fois au total.
Adapte ce repère à tes acquis et au soin apporté aux exercices. Les pauses, les reprises, la consultation des sources externes et les révisions suivantes s’ajoutent selon tes besoins.
Avec les ateliers, le projet, le quiz et les cartes : environ 2 h 45 à 4 h 40, à répartir sur plusieurs séances.
Objectifs du cours
Ce que tu vas savoir faire
- Distinguer mémoire, registres, unité de commande, unité arithmétique et logique, compteur ordinal, entrées et sorties.
- Dérouler le cycle charger-décoder-exécuter d'un jeu d'instructions simplifié et expliquer chaque changement d'état.
- Construire la table de vérité d'un demi-additionneur et d'un additionneur complet.
- Expliquer paquet, encapsulation, numéro de séquence, accusé de réception, perte et retransmission.
- Identifier noyau, shell et processus, résoudre un chemin et appliquer les classes propriétaire, groupe et autres.
- Relier capteur, donnée, contrôleur, actionneur, retour d'état et garde-fou sans commander de matériel réel.
Étape du cours · 8 à 15 min
Charger, décoder, exécuter : que change chaque instruction ?
Dans le modèle de von Neumann, une même mémoire contient instructions et données. Le processeur réunit l’unité de commande, l’unité arithmétique et logique (UAL) et des registres. Le compteur ordinal repère l’instruction à charger ; le registre d’instruction la conserve pendant son décodage. Des bus transportent adresses, données et signaux de contrôle. La RAM de travail est volatile, contrairement au stockage persistant d’un SSD. Un accumulateur est un registre de calcul, pas une case du disque.
Charger, décoder, exécuter : le compteur sélectionne une instruction, l’unité de commande interprète son opération et ses opérandes, puis le calcul ou le transfert modifie l’état. Le langage machine est codé en bits ; l’assembleur emploie des noms lisibles. Ici, ADD 1 ajoute le contenu de l’adresse 1, pas la valeur immédiate 1. JZ 2 choisit l’instruction 2 seulement si l’accumulateur vaut zéro. HALT arrête et compte comme un pas ; atteindre la limite sans arrêt produit une erreur.
Le simulateur sépare la liste d’instructions de la liste de données pour faciliter la lecture : il illustre le cycle, mais ne reproduit donc pas la mémoire unifiée de von Neumann. Ses entiers Python n’ont pas la largeur fixe d’un registre matériel. Il copie les données et trace l’état avant chaque instruction. Une architecture monoprocesseur possède un processeur ; plusieurs processeurs ou plusieurs cœurs permettent des exécutions parallèles, sans diviser automatiquement par leur nombre la durée de tout programme. Fréquence d’horloge et nombre d’instructions exécutées ne sont pas interchangeables.
Voir pour comprendre
D'une instruction à l'état suivant
Mémoire initiale [7, 5, 0], accumulateur initial 0.
- 1LOAD 0, compteur 0Lire mémoire[0] : l'accumulateur devient 7.
- 2ADD 1, compteur 1Lire mémoire[1] : l'accumulateur devient 7 + 5 = 12.
- 3STORE 2, compteur 2Écrire 12 en mémoire[2] : mémoire = [7, 5, 12].
- 4HALT, compteur 3Terminer et rendre l'état ainsi que la trace.
Lis le schéma. Nomme ce qui change à chaque étape : compteur, accumulateur ou mémoire. Quel état était visible juste avant ADD ?
Le compteur indique une instruction, pas une donnée calculée. Ce modèle séquentiel ne reproduit pas toute l'architecture matérielle.
Exemples résolus et erreurs expliquées
Calculer 7 + 5 et contrôler la branche
- Place
[7, 5, 0]dans les données et les instructionsLOAD 0,ADD 1,STORE 2,HALTaux indices 0 à 3. L’accumulateur et le compteur commencent à zéro. - À l’indice 0, LOAD lit 7. À l’indice 1, ADD lit 5 et donne 12. Le compteur change d’adresse tandis que l’accumulateur contient le résultat : ce sont deux rôles différents.
- STORE 2 écrit 12 dans la troisième case. HALT rend l’accumulateur 12, la copie
[7, 5, 12]et quatre états avant instruction. Les données initiales restent[7, 5, 0]. - Pour tester le saut, exécute
JZ 2,LOAD 0,HALT: l’accumulateur initial vaut zéro, donc les compteurs visités sont 0 puis 2. LOAD n’est jamais exécuté.
Conclusion. Le résultat, les données conservées et la liste des compteurs fournissent trois contrôles distincts.
Laboratoire de code
Languepython
Butdérouler un jeu d'instructions minimal et enregistrer compteur, instruction, accumulateur et mémoire
Code solution
def executer(programme, memoire, limite=50):
if type(limite) is not int or limite < 1:
raise ValueError('limite entière positive attendue')
if not isinstance(programme, (list, tuple)) or not isinstance(memoire, (list, tuple)):
raise ValueError('séquences attendues')
if any(type(x) is not int for x in memoire):
raise ValueError('données entières attendues')
pc, acc, trace = 0, 0, []
memoire = list(memoire)
for _ in range(limite):
if not 0 <= pc < len(programme):
raise IndexError('compteur hors programme')
instruction = programme[pc]
if not isinstance(instruction, (list, tuple)) or not instruction:
raise ValueError('instruction mal formée')
operation, *arguments = instruction
if operation not in ('LOAD', 'ADD', 'STORE', 'JZ', 'HALT'):
raise ValueError('instruction inconnue')
if operation == 'HALT':
if arguments:
raise ValueError('HALT sans opérande attendu')
else:
if len(arguments) != 1 or type(arguments[0]) is not int:
raise ValueError('une adresse entière attendue')
borne = len(programme) if operation == 'JZ' else len(memoire)
if not 0 <= arguments[0] < borne:
raise IndexError('adresse hors domaine')
trace.append({'pc': pc, 'instruction': tuple(instruction),
'acc_avant': acc, 'memoire': tuple(memoire)})
pc += 1
if operation == 'LOAD':
acc = memoire[arguments[0]]
elif operation == 'ADD':
acc += memoire[arguments[0]]
elif operation == 'STORE':
memoire[arguments[0]] = acc
elif operation == 'JZ' and acc == 0:
pc = arguments[0]
elif operation == 'HALT':
return acc, memoire, trace
raise RuntimeError('limite de pas atteinte')Tests
programme = [('LOAD',0),('ADD',1),('STORE',2),('HALT',)]
acc, memoire, trace = executer(programme,[7,5,0])
assert acc == 12
assert memoire == [7,5,12]
assert [etape['pc'] for etape in trace] == [0,1,2,3]
assert trace[1]['acc_avant'] == 7
assert programme == [('LOAD',0),('ADD',1),('STORE',2),('HALT',)]
try:
executer([('LOAD', -1), ('HALT',)], [7])
except IndexError:
pass
else:
raise AssertionError('entrée invalide acceptée')
try:
executer([('JZ', 0)], [])
except RuntimeError:
pass
else:
raise AssertionError('entrée invalide acceptée')
try:
executer([], [])
except IndexError:
pass
else:
raise AssertionError('entrée invalide acceptée')Trace
- pc=0 charge LOAD 0 : l'accumulateur passe de 0 à mémoire[0]=7
- pc=1 charge ADD 1 : l'UAL calcule 7+5 et acc devient 12
- pc=2 écrit 12 en mémoire[2], puis pc=3 charge HALT et rend état et trace
Clinique de bogue
Indice observéJUMP 2 avance de deux positions après l’incrément au lieu de choisir l’adresse 2.
CauseUne adresse absolue de saut est confondue avec un déplacement relatif. Ce petit parcours de contrôle, distinct du processeur ci-dessus, accepte seulement JUMP adresse et HALT. Il doit affecter le compteur, contrôler la cible et borner les pas.
Étape du cours · 6 à 13 min
Des booléens au circuit : comment additionner deux bits ?
Une porte logique réalise une fonction booléenne. NOT inverse un bit ; AND vaut 1 si les deux entrées valent 1 ; OR vaut 1 si au moins une vaut 1 ; XOR vaut 1 si elles diffèrent. Dans le modèle combinatoire idéal, les sorties dépendent des entrées présentes, sans état mémorisé. Une mémoire ou le compteur d’un processeur relève au contraire d’un comportement séquentiel.
Un demi-additionneur reçoit deux bits a et b. Son bit de somme vaut a XOR b et sa retenue a AND b. Un additionneur complet reçoit en plus une retenue entrante r : on additionne a et b, puis leur bit de somme et r. Les deux retenues intermédiaires sont combinées par OR. Elles ne sont pas ajoutées comme deux nouveaux bits faibles : chacune représente le poids suivant.
La relation à vérifier est a + b + r = somme + 2 * retenue. Les huit combinaisons possibles permettent un contrôle exhaustif de cette fonction à trois bits, pas de tous les circuits. Le code refuse booléens, flottants et valeurs autres que les entiers 0 et 1. Il ne décrit ni tensions ni délais physiques ; le circuit réel doit se stabiliser avant que sa sortie soit interprétée.
Exemples résolus et erreurs expliquées
Construire 1 + 0 avec une retenue entrante de 1
- Fixe a = 1, b = 0 et r = 1. Leur somme arithmétique vaut 2 ; tu attends donc le motif binaire 10, avec somme faible 0 et retenue 1.
- Le premier demi-additionneur reçoit 1 et 0 : XOR donne somme1 = 1 et AND donne retenue1 = 0. Il reste à inclure la retenue entrante.
- Le second reçoit somme1 = 1 et r = 1 : il donne somme2 = 0 et retenue2 = 1. Le OR de 0 et 1 fournit la retenue finale 1.
- Contrôle 1 + 0 + 1 = 0 + 2 × 1. Avec trois entrées à 1, le résultat est au contraire somme 1, retenue 1, soit 3. Ne remplace pas XOR par OR.
Table complète : entrées a, b, r ; sorties somme, retenue
a b r | somme retenue
0 0 0 | 0 0
0 0 1 | 1 0
0 1 0 | 1 0
0 1 1 | 0 1
1 0 0 | 1 0
1 0 1 | 0 1
1 1 0 | 0 1
1 1 1 | 1 1Conclusion. La retenue sortante a un poids double de celui du bit de somme.
Laboratoire de code
Languepython
Butcomposer un additionneur complet et vérifier exhaustivement son invariant
Code solution
def bit(x):
if type(x) is not int or x not in (0, 1):
raise ValueError('bit attendu')
return x
def demi_additionneur(a, b):
a, b = bit(a), bit(b)
return a ^ b, a & b
def additionneur_complet(a, b, retenue_entree):
somme1, retenue1 = demi_additionneur(a, b)
somme2, retenue2 = demi_additionneur(somme1, retenue_entree)
return somme2, retenue1 | retenue2
def table_complete():
return [(a,b,r,*additionneur_complet(a,b,r)) for a in (0,1) for b in (0,1) for r in (0,1)]Tests
assert demi_additionneur(0,0) == (0,0)
assert demi_additionneur(1,1) == (0,1)
assert additionneur_complet(1,0,1) == (0,1)
assert additionneur_complet(1,1,1) == (1,1)
assert len(table_complete()) == 8
assert all(a+b+r == somme+2*retenue for a,b,r,somme,retenue in table_complete())
try:
demi_additionneur(1.0, 0)
except ValueError:
pass
else:
raise AssertionError('entrée invalide acceptée')Trace
- pour a=1,b=0,r=1, le premier demi-additionneur produit somme1=1,retenue1=0
- le second additionne somme1=1 et r=1 : somme2=0,retenue2=1
- OR des retenues donne 1 et l'invariant 1+0+1 = 0+2×1 est vérifié
Clinique de bogue
Indice observépour 1 et 1, la somme renvoie 1 alors qu'elle doit être 0 avec une retenue 1
CauseOR vaut vrai dès qu'au moins une entrée vaut 1, tandis que le bit de somme doit valoir 1 lorsque les entrées diffèrent. L'opération correcte est XOR, pas OR.
Étape du cours · 7 à 13 min
Paquets et encapsulation : pourquoi découper un message ?
Sur le réseau local d’un lycée, une interface relie chaque poste au réseau. Un commutateur Ethernet transmet les trames au sein du réseau local ; un point d’accès permet la liaison Wi-Fi ; un routeur achemine les paquets IP entre réseaux. Un serveur fournit un service, ce n’est pas un synonyme de routeur. Une box peut réunir plusieurs rôles dans un même appareil.
Découper une grande donnée en unités facilite le partage du lien et, avec un protocole adapté, la retransmission des unités perdues. Encapsuler est une autre opération : chaque couche ajoute ses informations autour de la charge reçue. Exemple simplifié : données applicatives dans un segment TCP, segment dans un paquet IP, paquet dans une trame Ethernet. Les ports identifient des extrémités de transport ; les adresses IP servent à l’acheminement entre réseaux. Découpage et encapsulation ne chiffrent pas le contenu.
Le laboratoire découpe une chaîne Python par points de code, pas par octets UTF-8 ni par caractères visuels complexes. Il utilise les champs fictifs numero, total et charge, qui ne sont pas les en-têtes TCP réels. Il traite un seul message à la fois. Le réassemblage vérifie types, intervalle, total commun et unicité avant de concaténer. Une liste vide représente ici le message vide : seule, elle ne permet pas de détecter la perte de tous les paquets d’un message attendu.
Exemples résolus et erreurs expliquées
Réassembler ALGORITHME arrivé dans le désordre
- Découpe ALGORITHME par groupes d’au plus trois points de code : ALG, ORI, THM, E. Les numéros vont de 0 à 3 et chaque paquet annonce total = 4.
- Suppose l’arrivée 2, 0, 3, 1. Construis l’index numéro → charge : 2 → THM, 0 → ALG, 3 → E, 1 → ORI. Ne concatène pas encore.
- Vérifie que chaque numéro est entier, présent une fois et compris entre 0 et 3. Les totaux concordent ; les quatre numéros attendus sont présents.
- Lis ensuite les charges dans l’ordre 0, 1, 2, 3 : ALG + ORI + THM + E = ALGORITHME. Retirer ORI doit provoquer une erreur, pas produire un mot raccourci.
Encapsulation : trois enveloppes, pas trois découpages
Trame Ethernet
En-tête de liaison
Paquet IP
En-tête IP
Segment TCP
En-tête TCP
Données applicatives
Contrôle de trameConclusion. Le numéro ordonne, le total aide à vérifier la complétude ; aucun champ ne recrée une donnée absente.
Laboratoire de code
Languepython
Butfragmenter, réordonner et réassembler avec contrôles de complétude
Code solution
def fragmenter(message, taille):
if type(message) is not str or type(taille) is not int or taille < 1:
raise ValueError('texte et taille entière positive attendus')
fragments = [message[i:i+taille] for i in range(0, len(message), taille)]
total = len(fragments)
return [{'numero': i, 'total': total, 'charge': f} for i, f in enumerate(fragments)]
def reassembler(paquets):
if type(paquets) is not list:
raise ValueError('liste de paquets attendue')
if not paquets:
return ''
total, index = None, {}
for p in paquets:
if type(p) is not dict or set(p) != {'numero', 'total', 'charge'}:
raise ValueError('champs de paquet invalides')
numero, annonce, charge = p['numero'], p['total'], p['charge']
if type(annonce) is not int or annonce < 1 or type(numero) is not int:
raise ValueError('entiers de séquence attendus')
if not 0 <= numero < annonce or type(charge) is not str or not charge:
raise ValueError('numéro ou charge invalide')
if total is None:
total = annonce
if annonce != total or numero in index:
raise ValueError('total incohérent ou doublon')
index[numero] = charge
if len(index) != total:
raise ValueError('fragment manquant')
return ''.join(index[i] for i in range(total))Tests
paquets = fragmenter('ALGORITHME',3)
assert [p['charge'] for p in paquets] == ['ALG','ORI','THM','E']
assert all(p['total'] == 4 for p in paquets)
assert reassembler(list(reversed(paquets))) == 'ALGORITHME'
assert fragmenter('',3) == []
assert reassembler([]) == ''
assert [p['numero'] for p in paquets] == [0,1,2,3]Trace
- ALGORITHME est découpé aux indices 0,3,6,9 en quatre charges
- chaque paquet reçoit son numéro et total=4 ; l'ordre d'arrivée peut être inversé
- reassembler construit l'index 0..3, vérifie qu'aucun numéro ne manque puis concatène ALG+ORI+THM+E
Clinique de bogue
Indice observédes paquets arrivés dans l'ordre 2,0,1 produisent un message mélangé et un fragment manquant passe inaperçu
CauseL'ordre de la liste d'arrivée est confondu avec le numéro de séquence. Le protocole doit indexer, vérifier unicité et complétude, puis lire les numéros dans l'ordre.
Étape du cours · 8 à 15 min
Perte et retransmission : comment éviter de livrer deux fois ?
Quand un accusé de réception (ACK) se perd, l’émetteur ne sait pas si la donnée a été reçue. Il attend une durée limite puis retransmet. Pour distinguer nouveau message et répétition, le bit alterné utilise des numéros 0 puis 1. L’émetteur n’a qu’un message non acquitté à la fois. Le destinataire mémorise un bit attendu, indépendamment du contenu du message : deux messages légitimes peuvent contenir exactement le même texte.
Si le numéro reçu est attendu, le destinataire livre la donnée à l’application et inverse son bit attendu. Sinon il reconnaît la retransmission et ne livre rien de nouveau. Dans les deux cas, il renvoie l’ACK portant le numéro reçu. L’émetteur n’avance qu’après l’ACK du message en attente. Ainsi perdre l’ACK 0 puis recevoir encore la donnée 0 ne déclenche pas une seconde livraison.
Le modèle choisit les pertes par numéros de tentatives, à partir de zéro. Une tentative suivante représente ici l’expiration du délai, sans attente réelle. Les canaux peuvent perdre un message ou un ACK, mais ne corrompent ni ne retardent des copies à travers plusieurs cycles de bits. Sous ces hypothèses, chaque donnée acquittée est livrée une fois ; des pertes persistantes peuvent empêcher la terminaison. La borne arrête la simulation avec une erreur, sans promettre que tout message sera livré. TCP réel emploie notamment des numéros portant sur un flux d’octets.
Voir pour comprendre
Un accusé perdu ne livre pas deux fois
Scénario : A avec le bit 0 est livré, mais son accusé n'arrive pas à l'émetteur.
| Événement reçu | Réception | Accusé |
|---|---|---|
| A, bit 0 attendu | livrer A ; attendre ensuite 1 | ACK 0 perdu |
| A, bit 0 retransmis | reconnaître le doublon ; ne pas relivrer | renvoyer ACK 0 |
| B, bit 1 attendu | livrer B ; attendre ensuite 0 | envoyer ACK 1 |
Lis le schéma. Suis séparément la livraison de la donnée et le retour de l'accusé. Pourquoi le destinataire accuse-t-il encore un doublon ?
L'émetteur doit pouvoir terminer son attente. La retransmission répare une perte d'accusé sans ajouter une seconde livraison.
Exemples résolus et erreurs expliquées
Deux contenus identiques, deux livraisons légitimes
- Prépare les messages A puis A. Émetteur et destinataire commencent au bit 0. La tentative 0 livre le premier A, mais son ACK est volontairement perdu.
- La tentative 1 renvoie A, bit 0. Le destinataire attend désormais 1 : il ne livre pas de seconde copie du premier message et renvoie ACK 0.
- Après ACK 0, l’émetteur passe au bit 1 et envoie le second A à la tentative 2. Ce bit est attendu ; le destinataire livre ce second message.
- Le bilan est donc deux A livrés, et non un ni trois. Déduire le doublon de la seule égalité du texte supprimerait un message légitime.
Conclusion. Le protocole compare un état de séquence, pas la ressemblance des contenus.
Laboratoire de code
Languepython
Butsuivre deux états de séquence avec pertes déterministes, doublons et arrêt borné
Code solution
def recevoir(etat, bit, message):
if type(bit) is not int or bit not in (0, 1) or type(message) is not str:
raise ValueError('bit entier et message texte attendus')
if type(etat) is not dict or type(etat.get('attendu')) is not int or etat['attendu'] not in (0, 1):
raise ValueError('état de réception invalide')
if type(etat.get('livres')) is not list or any(type(x) is not str for x in etat['livres']):
raise ValueError('livraisons invalides')
livres = list(etat['livres'])
attendu = etat['attendu']
if bit == attendu:
livres.append(message)
attendu = 1 - attendu
return {'attendu': attendu, 'livres': livres}, bit
def transmettre(messages, pertes_paquet=frozenset(), pertes_ack=frozenset(), limite=100):
if type(messages) is not list or any(type(x) is not str for x in messages):
raise ValueError('liste de textes attendue')
if type(limite) is not int or limite < 1:
raise ValueError('limite entière positive attendue')
for pertes in (pertes_paquet, pertes_ack):
if not isinstance(pertes, (set, frozenset)) or any(type(x) is not int or x < 0 for x in pertes):
raise ValueError('ensemble de tentatives attendu')
etat = {'attendu': 0, 'livres': []}
trace, bit, tentative = [], 0, 0
for message in messages:
acquitte = False
while not acquitte:
if tentative >= limite:
raise RuntimeError('trop de tentatives')
if tentative in pertes_paquet:
trace.append((tentative, bit, 'paquet_perdu'))
else:
nouveau = bit == etat['attendu']
etat, ack = recevoir(etat, bit, message)
trace.append((tentative, bit, 'livre' if nouveau else 'doublon_non_livre'))
if tentative in pertes_ack:
trace.append((tentative, bit, 'ack_perdu'))
else:
acquitte = ack == bit
trace.append((tentative, bit, 'ack_recu'))
tentative += 1
bit = 1 - bit
return etat['livres'], traceTests
livres, trace = transmettre(['A','B'], pertes_paquet={0}, pertes_ack={2})
assert livres == ['A','B']
assert any(e[2] == 'paquet_perdu' for e in trace)
assert any(e[2] == 'ack_perdu' for e in trace)
assert any(e[2] == 'doublon_non_livre' for e in trace)
assert [e[1] for e in trace if e[2] == 'livre'] == [0,1]
assert transmettre([])[0] == []Trace
- tentative 0, bit 0 : paquet perdu, aucune livraison ni accusé
- tentative 1 : A est livré une fois et ack 0 arrive ; l'émetteur passe au bit 1
- B est livré mais son ack se perd ; la retransmission du même bit est reconnue comme doublon, puis accusée sans seconde livraison
Clinique de bogue
Indice observési l'accusé se perd, la retransmission ajoute une seconde copie du même message
CauseLe destinataire ne mémorise aucun numéro attendu. Il ne peut donc distinguer un nouveau message d'une retransmission provoquée par la perte de l'accusé précédent.
Étape du cours · 8 à 15 min
Système d'exploitation : chemin, abstraction et droit d'accès
Le système d’exploitation arbitre l’accès au processeur, à la mémoire, aux fichiers et aux périphériques. Un programme est un ensemble d’instructions ; un processus est une exécution de ce programme avec son état. Plusieurs processus peuvent progresser par alternance sur un cœur. Le noyau gère les ressources ; le shell interprète des commandes ; le terminal affiche les échanges avec le shell. Ces trois éléments ne sont pas synonymes.
Un chemin absolu part de /, un chemin relatif du répertoire courant. . désigne ce répertoire et .. son parent. La normalisation ci-dessous calcule un chemin dans un arbre fictif sans liens symboliques ; elle ne prouve ni existence ni accès. Le modèle de cd vérifie ensuite que la destination est un répertoire de cet arbre. Sur un vrai Unix, chaque composant du chemin doit être résolu et les permissions de traversée doivent aussi être contrôlées.
Les droits d’un fichier ordinaire sont répartis en trois classes : propriétaire, groupe du fichier, autres. On choisit une seule classe, dans cet ordre, sans additionner leurs droits. r autorise la lecture, w l’écriture, x l’exécution. Pour un répertoire, r permet de lister des noms, x de le traverser, et la création ou suppression d’entrées nécessite normalement w avec x. Les ACL, privilèges, liens et règles particulières de suppression ne sont pas modélisés.
Les commandes pwd, ls, cd, mkdir, cp, mv et chmod servent respectivement à situer, lister, se déplacer, créer un dossier, copier, déplacer ou renommer, puis changer des droits. Une modification de permissions ne chiffre pas un fichier. Libre ne veut pas dire gratuit : les libertés d’exécuter, étudier, modifier et redistribuer dépendent de la licence. GNU/Linux associe notamment un noyau Linux et des outils ; une interface graphique n’est pas ce qui rend un système libre.
Voir pour comprendre
Choisir les droits sans les cumuler
Fichier d’Alice, groupe nsi : propriétaire r--, groupe rw-, autres rwx. Ce cas teste la priorité, pas un réglage recommandé.
| Demandeur | Classe retenue | Écrire ? |
|---|---|---|
| Alice, aussi dans nsi | propriétaire : r-- | non |
| Bob, dans nsi | groupe : rw- | oui |
| Camille, hors nsi | autres : rwx | oui |
Lis le schéma. Compare Alice et Bob. Pourquoi les droits plus larges du groupe ne donnent-ils pas w à Alice ?
La première classe applicable décide : propriétaire, sinon groupe, sinon autres. Un refus n’autorise pas à essayer la classe suivante.
Exemples résolus et erreurs expliquées
Lire un chemin, puis les trois classes de droits
- Dans l’arbre fictif
/atelier/nsiet/atelier/images, pars de/atelier/nsi. Le chemin../imagesretire nsi puis ajoute images : la destination calculée est/atelier/images. - Considère
-rw-r-----pour un fichier appartenant à Alice et au groupe nsi. Le premier signe décrit un fichier ordinaire ; les trois triplets sont rw-, r-- et ---. - Alice peut écrire ; Bob, membre de nsi sans être propriétaire, peut lire mais pas écrire ; une personne extérieure n’a aucun de ces droits. On ne retombe pas sur autres si la classe choisie refuse l’action.
- Le mode 640 correspond à 6 = 4 + 2, 4 = 4 et 0.
chmod 640 notes.txtremplace les neuf bits ordinaires ;chmod g+w notes.txtajoute seulement w au groupe. Dans les deux cas, vérifie ensuite avecls -l.
Repères de terminal GNU/Linux : observation sans modification de fichier
pwd # affiche le répertoire courant
ls -l . # observe les entrées et leurs permissions
cd . # reste dans le répertoire courant
pwd # contrôle la position
man chmod # consulte la documentation ; q pour quitterConclusion. Un chemin valide ne donne pas de droit. La simulation ne modifie que des dictionnaires, jamais les fichiers du poste.
Laboratoire de code
Languepython
Butrésoudre un chemin fictif, vérifier une destination et appliquer trois classes de droits
Code solution
def normaliser(chemin, courant='/'):
if type(chemin) is not str or not chemin or '\0' in chemin:
raise ValueError('chemin non vide attendu')
if type(courant) is not str or not courant.startswith('/') or '\0' in courant:
raise ValueError('répertoire courant absolu attendu')
complet = chemin if chemin.startswith('/') else courant + '/' + chemin
morceaux = []
for morceau in complet.split('/'):
if morceau in ('', '.'):
continue
if morceau == '..':
if morceaux:
morceaux.pop()
else:
morceaux.append(morceau)
return '/' + '/'.join(morceaux)
def autorise(fichier, utilisateur, action, groupes=()):
if type(fichier) is not dict:
raise ValueError('fiche de permissions attendue')
if type(action) is not str or action not in ('r', 'w', 'x'):
raise ValueError('action r, w ou x attendue')
if type(utilisateur) is not str or not utilisateur:
raise ValueError('identité fictive attendue')
if not isinstance(groupes, (list, tuple, set, frozenset)) or any(type(g) is not str for g in groupes):
raise ValueError('collection de groupes attendue')
for cle in ('owner', 'groupe'):
if type(fichier.get(cle)) is not str or not fichier[cle]:
raise ValueError('propriétaire et groupe attendus')
for cle in ('proprietaire', 'droits_groupe', 'autres'):
droits = fichier.get(cle)
if type(droits) is not str or any(c not in 'rwx' for c in droits) or len(set(droits)) != len(droits):
raise ValueError('droits invalides')
if utilisateur == fichier['owner']:
droits = fichier['proprietaire']
elif fichier['groupe'] in groupes:
droits = fichier['droits_groupe']
else:
droits = fichier['autres']
return action in droits
def simuler_cd(courant, argument, repertoires):
destination = normaliser(argument, courant)
if destination not in repertoires:
raise ValueError('répertoire absent de cet arbre fictif')
return destination
def mode_ordinaire(mode):
if type(mode) is not str or len(mode) != 3 or any(c not in '01234567' for c in mode):
raise ValueError('trois chiffres octaux attendus')
return [''.join(droit for poids, droit in ((4, 'r'), (2, 'w'), (1, 'x')) if int(c) & poids)
for c in mode]Tests
assert normaliser('../images/./logo.png','/cours/nsi') == '/cours/images/logo.png'
assert normaliser('/a//b/../c') == '/a/c'
assert normaliser('../../x','/') == '/x'
assert simuler_cd('/atelier/nsi','..', {'/', '/atelier', '/atelier/nsi'}) == '/atelier'
f = {'owner':'alice','groupe':'nsi','proprietaire':'rw','droits_groupe':'r','autres':''}
assert autorise(f,'alice','w', ['nsi'])
assert autorise(f,'bob','r', ['nsi'])
assert not autorise(f,'bob','w', ['nsi'])
assert not autorise(f,'camille','r')
assert mode_ordinaire('640') == ['rw', 'r', '']
for chemin in ('', None):
try:
normaliser(chemin)
except ValueError:
pass
else:
raise AssertionError('chemin invalide accepté')Trace
- Depuis /cours/nsi, .. retire nsi ; images puis logo.png complètent /cours/images/logo.png.
- Pour Bob membre de nsi, la classe groupe est choisie : elle contient r mais pas w.
- Le mode 640 se décompose en rw, r et aucun droit ; l’existence du fichier reste une autre question.
Clinique de bogue
Indice observéDes droits appartenant à d’autres classes accordent une action refusée à la classe du demandeur.
CauseLes trois triplets ne constituent pas une réserve commune. La classe propriétaire est prioritaire, même lorsque le groupe ou les autres ont plus de droits. Le test doit choisir une classe, puis contrôler une seule action dans cette classe.
Étape du cours · 7 à 15 min
Capteur, actionneur, IHM : où placer les garde-fous ?
Un capteur convertit une grandeur physique en signal exploitable ; la chaîne d’acquisition fournit une donnée avec une unité. Un actionneur produit un effet physique à partir d’une commande. Le contrôleur applique une règle et l’IHM permet à une personne de voir l’état ou de modifier une consigne. Une valeur affichée n’est pas automatiquement une mesure récente, ni une preuve que l’actionneur a réellement obéi.
Nous étudions un éclairage fictif : en dessous de 200 lux il s’allume, au-dessus de 300 il s’éteint, et entre ces seuils inclus il conserve l’état précédent. C’est l’hystérésis. À 250 lux, allumé et éteint sont donc tous deux possibles selon l’histoire. Les seuils sont des paramètres pédagogiques, pas des recommandations d’installation ; l’unité lux décrit l’éclairement, pas une température.
Le code vérifie l’état précédent, des seuils numériques ordonnés, une mesure finie entre 0 et 200 000 lux et un âge logique compris entre 0 et 5 inclus. Une date future ou trop ancienne rend la mesure inutilisable. L’étiquette abstraite arrêter signale une erreur dans la simulation, sans décider d’un état sûr universel pour un appareil réel. L’IHM textuelle annonce la mesure, son âge et la commande, ou la raison du refus. Le projet ne connecte aucun dispositif.
Voir pour comprendre
Deux seuils : la même mesure peut conserver deux états
Modèle d'éclairage sans matériel : seuil bas 200 lux, seuil haut 300 lux.
| Mesure | État précédent | Commande simulée |
|---|---|---|
| 199 lux | éteint | allumé |
| 250 lux | allumé | allumé |
| 250 lux | éteint | éteint |
| 301 lux | allumé | éteint |
Lis le schéma. Compare les deux lignes à 250 lux. Quelle information manque si tu ne connais que la mesure ?
Entre les seuils inclus, l'hystérésis conserve l'état. Cette règle fictive ne valide ni un capteur ni la sécurité d'un appareil réel.
Exemples résolus et erreurs expliquées
Suivre 199, 250 puis 301 lux sans oscillation
- Commence à l’état éteint avec une mesure fraîche de 199 lux. La valeur est strictement inférieure à 200 : le modèle demande allumé.
- Prends ensuite 250 lux et conserve allumé comme état précédent. La valeur est entre les deux seuils inclus : la commande reste allumé.
- À 301 lux, la valeur dépasse strictement 300 : la commande devient éteint. À 200 ou 300 exactement, l’état antérieur aurait été conservé.
- Reçois enfin 100 lux mesurés à t = 2 alors que t = 8 : l’âge vaut 6, donc le modèle refuse la mesure et affiche arrêter. Il ne réutilise pas la dernière commande comme si la donnée était fraîche.
Conclusion. La décision dépend de la mesure, de son âge et de l’état précédent, pas d’un seuil unique.
Laboratoire de code
Languepython
Butdécider dans une simulation avec unité, domaine, hystérésis et état sûr
Code solution
import math
def commander_eclairage(lux, etat, seuil_bas=200, seuil_haut=300, temps_mesure=0, temps_courant=0):
def nombre(x):
return type(x) is int or (type(x) is float and math.isfinite(x))
for seuil in (seuil_bas, seuil_haut):
if not nombre(seuil) or not 0 <= seuil <= 200000:
raise ValueError('seuil numérique dans le domaine attendu')
if not seuil_bas < seuil_haut:
raise ValueError('seuils incohérents')
erreur = None
if etat not in ('allume', 'eteint'):
erreur = 'état précédent invalide'
elif not nombre(lux) or not 0 <= lux <= 200000:
erreur = 'mesure invalide ou hors domaine'
elif type(temps_mesure) is not int or type(temps_courant) is not int or temps_mesure < 0 or temps_courant < 0:
erreur = 'temps logique invalide'
elif not 0 <= temps_courant - temps_mesure <= 5:
erreur = 'mesure future ou périmée'
if erreur:
return {'commande': 'arreter', 'erreur': erreur}
if lux < seuil_bas:
nouvel_etat = 'allume'
elif lux > seuil_haut:
nouvel_etat = 'eteint'
else:
nouvel_etat = etat
return {'commande': nouvel_etat, 'erreur': None, 'mesure_lux': lux,
'age': temps_courant - temps_mesure}
def modele_ihm(resultat):
if resultat['erreur']:
return f"Simulation arrêtée : {resultat['erreur']}"
return (f"Éclairage {resultat['commande']}, mesure {resultat['mesure_lux']} lux, "
f"âge logique {resultat['age']}")Tests
assert commander_eclairage(100,'eteint')['commande'] == 'allume'
assert commander_eclairage(400,'allume')['commande'] == 'eteint'
assert commander_eclairage(250,'allume')['commande'] == 'allume'
assert commander_eclairage(250,'eteint')['commande'] == 'eteint'
assert commander_eclairage('inconnue','allume')['commande'] == 'arreter'
assert 'lux' in modele_ihm(commander_eclairage(100,'eteint'))
assert modele_ihm(commander_eclairage(-1,'allume')).startswith('Simulation arrêtée')
assert commander_eclairage(100,'eteint',temps_mesure=2,temps_courant=7)['commande'] == 'allume'
assert commander_eclairage(100,'eteint',temps_mesure=2,temps_courant=8)['commande'] == 'arreter'Trace
- mesure 250 lux est numérique, dans le domaine et entre les seuils 200 et 300
- la zone d'hystérésis conserve l'état précédent plutôt que changer à chaque petite variation
- une mesure -1 sort du domaine et produit la commande abstraite arrêter avec un message, jamais une action physique
Clinique de bogue
Indice observéautour de 250, une petite variation alterne rapidement les commandes et une mesure invalide peut provoquer une exception ou une décision trompeuse
CauseUn seuil unique sans état peut faire alterner les commandes à chaque petite variation. Ce correctif isolé suppose une mesure fraîche : il valide type, domaine et état puis emploie deux seuils. Le laboratoire complet traite en plus les temps logiques et les erreurs.
Poursuivre avec l’abonnement
Passer de la lecture à la pratique
Suis les six explications, les quatre schémas et les exemples résolus.
Entraîne-toi avec six ateliers, dix questions corrigées, douze cartes et un projet de station simulée.
10 questions · 12 cartes. Ta reprise et tes révisions sont enregistrées dans ce navigateur. Elles ne se synchronisent pas entre appareils.
Accéder à l'entraînement Déjà abonné ? Se connecterVérifier et prolonger
Sources du cours
Édition Maxdecours · Vérifié le .
Spécialité NSI, Première générale · programme du BO spécial du 22 janvier 2019
- Programme officiel NSI Premièrearchitecture, réseau, système d'exploitation, permissions et périphériques · consulté le 2026-09-05
- Éduscol, programmes et ressources NSIétat en vigueur et ressources d'accompagnement · consulté le 2026-09-05
- Éduscol, Modèle d'architecture de von Neumannconstituants et déroulement d'instructions simples · consulté le 2026-09-05
- Éduscol, Systèmes de type UNIX, point de vue utilisateurarborescence, chemins, commandes et permissions · consulté le 2026-09-05
- IETF, Transmission Control Protocol RFC 9293référence primaire pour distinguer le protocole pédagogique de TCP réel · consulté le 2026-09-05
- POSIX, définitions des classes d’accès aux fichierspriorité propriétaire, groupe du fichier et autres · consulté le 2026-09-05
- Linux man-pages, résolution des cheminsrésolution réelle, répertoires, traversée et limites du modèle lexical · consulté le 2026-09-05
- GNU, définition du logiciel librelibertés distinctes du prix · consulté le 2026-09-05
- Cisco, fonctions des équipements réseaucommutateur, routeur et point d’accès · consulté le 2026-09-05
- Python, fonctions mathématiquescontrôle des valeurs flottantes finies · consulté le 2026-09-05
© 2026 Maxdecours.com · Comprendre et progresser