Station MinuitPortail personnel de révision

IFT-2001 — Systèmes d’exploitationAutomne 2026

Semaine 4 — Threads

8. Sûreté concurrente et conditions de concurrence

LECTURE 11 / 196 repèresSynthèse avec omissions acceptées

8. Sûreté concurrente et conditions de concurrence

8.1 Fonction thread-safe et fonction réentrante

Une fonction est thread-safe si plusieurs threads peuvent l’utiliser concurremment dans les conditions documentées sans course ni corruption. La garantie peut autoriser plusieurs lecteurs mais interdire des écritures simultanées.

Deux familles de stratégies existent :

  • éviter l’état mutable partagé : variables locales, objets immuables, tampon fourni par l’appelant, stockage local au thread;
  • contrôler cet état : mutex, opérations atomiques et autres primitives de synchronisation.

La réentrance est liée, mais différente. Une fonction protégée par un mutex peut être sûre entre threads sans être réentrante dans un gestionnaire de signal ou d’interruption. Inversement, une fonction sans variable globale facilite la réentrance, mais son appelant peut encore partager incorrectement un objet externe.

Une variable locale static ne vit pas dans la pile propre au thread. Elle est partagée entre appels et peut être écrasée par un second participant. Il faut employer une variante réentrante, un tampon par appelant, du stockage local au thread ou une protection explicite selon le contrat.

8.2 Condition de concurrence

Une instruction de haut niveau comme compteur++ peut devenir une séquence :

  1. lire la mémoire;
  2. calculer une nouvelle valeur dans un registre;
  3. réécrire la mémoire.

Une interruption peut survenir entre ces étapes. Si un autre thread manipule la même donnée, le résultat dépend de l’entrelacement. Une condition de concurrence existe lorsque le résultat observable dépend de cet ordre imprévisible.

Une section critique est une portion de code qui accède à une ressource commune et qui ne doit pas être exécutée simultanément par plusieurs participants. Une solution d’exclusion comporte conceptuellement une entrée, la section critique, une sortie et le reste du code non critique.

8.3 Exemple du spouleur

Une variable partagée N désigne la prochaine case libre du tableau d’impression.

  1. A lit N = 7, puis est interrompu.
  2. B lit aussi 7, écrit son travail dans la case 7 et incrémente N.
  3. A reprend avec sa copie locale 7 et écrase la même case.

Le document de B disparaît sans erreur nécessairement visible. La section critique doit couvrir ensemble la lecture de N, l’écriture de la case et la mise à jour de N; protéger seulement une étape ne préserve pas l’invariant.

8.4 Exemple du compteur

Deux threads exécutent des incréments sur une globale. Au maximum, aucune mise à jour n’est perdue et le résultat vaut deux fois le nombre d’itérations. Dans un entrelacement défavorable, plusieurs lectures utilisent la même ancienne valeur et une écriture en écrase une autre; le résultat se rapproche d’un seul lot d’incréments. De nombreuses valeurs intermédiaires sont possibles.

Un pthread_join après les créations attend la fin des deux threads, mais ne protège aucune opération pendant leur exécution. Un join immédiat supprimerait la course en sérialisant tout, au prix du parallélisme. Une exclusion fine — développée dans le module Concurrence — doit protéger uniquement la mise à jour partagée.

8.5 Communication entre processus et entre threads

Deux processus isolés établissent un canal explicite : mémoire partagée, tube, fichier ou réseau. Un pipe relie typiquement la sortie d’un programme à l’entrée d’un autre. Les threads possèdent déjà un canal par le tas et les globales, mais cette commodité rend les conflits plus faciles.

Le problème doit être décomposé :

  1. établir le partage ou le canal;
  2. exclure les accès incompatibles;
  3. synchroniser les dépendances, par exemple un consommateur qui attend une donnée du producteur.
Retour au sommaire de l’unitéHaut de page
Récupérer manuellement les données locales

Copier séparément les données ci-dessous dans des fichiers texte avant de fermer la page ou de modifier le stockage. Une valeur illisible ou incompatible reste en place. Aucun effacement ni rétablissement écrasant n’est effectué automatiquement. L’export/import JSON est disponible sur la page Progression du cours. Cette récupération séparée reste utile pour une valeur brute ou un conflit.

Clé de ce cours : . Format v1 porté par cette clé; dates UTC et identifiants durables.

Si l’accès est refusé, la valeur persistée peut rester inaccessible. Réautoriser le stockage dans le navigateur puis rouvrir ce cours permet de la relire. Une réinitialisation exige une décision explicite après récupération; aucune commande de suppression n’est proposée ici. Les données restent sur cette origine et cet appareil, sans transfert automatique.