{
  "chapter": {
    "id": "processus-systeme",
    "level": "terminale",
    "theme": "Architectures",
    "title": "Processus et système",
    "description": "Approfondissement de la gestion des processus par\nun système d'exploitation : notion de processus,\nétats, ordonnancement, communication entre\nprocessus, synchronisation par verrous, risque\nd'interblocage et notion de signal.",
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "processus"
      ],
      "title": "Notion de processus",
      "statement": "Qu'est-ce qu'un **processus** ?",
      "options": [
        {
          "text": "Un programme en cours d'exécution, accompagné de sa mémoire, de ses ressources et de son contexte (registres, pile d'appels)",
          "correct": true,
          "feedback": "C'est une abstraction centrale du\nsystème d'exploitation. Un même\nprogramme lancé deux fois donne\ndeux processus indépendants, qui\ndisposent chacun de leur propre\nmémoire et de leur propre contexte\nd'exécution.\n"
        },
        {
          "text": "Un type particulier de mémoire",
          "correct": false,
          "feedback": "Un processus utilise de la mémoire\n(sa zone de mémoire), mais il\nn'est pas lui-même un type de\nmémoire.\n"
        },
        {
          "text": "Un fichier exécutable stocké sur le disque",
          "correct": false,
          "feedback": "Cette description correspond plutôt\nà un **programme** au sens du\nfichier exécutable. Un processus\nest, lui, dynamique : il représente\nun programme **en cours\nd'exécution**.\n"
        },
        {
          "text": "Une fonction définie dans un programme Python",
          "correct": false,
          "feedback": "Une fonction n'est qu'un fragment\nde code à l'intérieur d'un\nprogramme. Un processus est une\nnotion bien plus large, qui\nenglobe l'intégralité d'un\nprogramme en exécution.\n"
        }
      ],
      "explanation": "Il faut bien distinguer la notion de\n**programme** (un fichier exécutable\nsur le disque) et celle de **processus**\n(une instance dynamique de ce programme\nen cours d'exécution). Sous Linux, les\ncommandes `ps` ou `top` permettent\nd'observer les processus actifs ; sous\nWindows, on utilise le Gestionnaire des\ntâches."
    },
    {
      "id": "q02",
      "difficulty": 1,
      "skills": [
        "thread"
      ],
      "title": "Fil d'exécution",
      "statement": "Qu'est-ce qu'un **fil d'exécution**\n(parfois appelé *thread*) ?",
      "options": [
        {
          "text": "Un protocole utilisé sur Internet",
          "correct": false,
          "feedback": "Un fil d'exécution est une notion\ninterne au système d'exploitation,\nsans rapport avec les protocoles\nréseau.\n"
        },
        {
          "text": "Une unité d'exécution légère au sein d'un processus, qui partage la mémoire avec les autres fils du même processus",
          "correct": true,
          "feedback": "Plusieurs fils d'exécution dans un\nmême processus permettent de\nparalléliser des tâches tout en\npartageant les données. Cette\napproche est plus légère que de\ncréer plusieurs processus, mais\nplus délicate à gérer en raison\ndes problèmes de synchronisation.\n"
        },
        {
          "text": "Un fichier de configuration du système",
          "correct": false,
          "feedback": "Cette description ne correspond pas\nà la notion de fil d'exécution,\nqui désigne une unité d'exécution\nau sein d'un programme.\n"
        },
        {
          "text": "Un type de fichier sur le disque",
          "correct": false,
          "feedback": "Un fil d'exécution n'a aucune\nexistence sur le disque. C'est une\nnotion d'exécution qui n'apparaît\nqu'à l'instant où un programme\ntourne.\n"
        }
      ],
      "explanation": "Une comparaison utile : un processus\nest comparable à une maison\nindépendante (sa mémoire est isolée),\ntandis qu'un fil d'exécution est\ncomparable à une pièce dans cette\nmaison (la mémoire reste partagée\navec les autres pièces)."
    },
    {
      "id": "q03",
      "difficulty": 1,
      "skills": [
        "pid"
      ],
      "title": "Identifiant de processus",
      "statement": "Que désigne le **PID** d'un processus ?",
      "options": [
        {
          "text": "Un pilote interne pour gérer les processus",
          "correct": false,
          "feedback": "Cette interprétation est\nfantaisiste. Le sigle PID désigne\nsimplement un identifiant\nnumérique unique attribué par le\nsystème.\n"
        },
        {
          "text": "Un numéro unique attribué par le système d'exploitation à chaque processus pour pouvoir l'identifier",
          "correct": true,
          "feedback": "Le PID, pour *Process IDentifier*,\npermet d'identifier les processus\nde manière unique. On l'utilise\npar exemple avec la commande\n`kill <PID>`. Sur les systèmes\nUnix, le numéro $1$ est\ntraditionnellement attribué au\nprocessus de démarrage.\n"
        },
        {
          "text": "Un descripteur de permissions",
          "correct": false,
          "feedback": "Les permissions et le PID sont des\nnotions distinctes. Le PID\nidentifie un processus ; les\npermissions définissent ce que ce\nprocessus peut faire.\n"
        },
        {
          "text": "Un domaine personnel sur Internet",
          "correct": false,
          "feedback": "Aucun rapport avec les domaines\nInternet. Le PID est un numéro\ninterne au système d'exploitation.\n"
        }
      ],
      "explanation": "Sur les systèmes Unix, la commande\n`ps` affiche les PID en cours.\n`kill <PID>` envoie le signal\n`TERM` par défaut, et\n`kill -9 <PID>` envoie le signal\n`KILL`, qui est plus brutal et ne\npeut pas être ignoré par le\nprocessus visé."
    },
    {
      "id": "q04",
      "difficulty": 1,
      "skills": [
        "etat-processus"
      ],
      "title": "États d'un processus",
      "statement": "Quels sont les **états principaux** par\nlesquels passe un processus au cours de\nsa vie ?",
      "options": [
        {
          "text": "Démarré et terminé, uniquement",
          "correct": false,
          "feedback": "Ces deux états ne suffisent pas à\ndécrire le cycle de vie d'un\nprocessus. Un processus peut être\nprêt à s'exécuter, en train de\ns'exécuter, ou bloqué en attente\nd'une ressource.\n"
        },
        {
          "text": "Sain et malade",
          "correct": false,
          "feedback": "Cette description fantaisiste n'a\naucun rapport avec la gestion des\nprocessus.\n"
        },
        {
          "text": "Prêt, en exécution, bloqué (en attente d'une ressource ou d'une entrée-sortie), terminé",
          "correct": true,
          "feedback": "C'est le modèle classique en\nsystème d'exploitation.\nL'ordonnanceur gère les\ntransitions entre l'état « prêt »\net l'état « en exécution ».\nL'état « bloqué » correspond à\nl'attente d'une ressource (un\nfichier, le réseau, un verrou).\n"
        },
        {
          "text": "Visible et caché",
          "correct": false,
          "feedback": "La visibilité d'un processus pour\nl'utilisateur n'a pas grand\nrapport avec son cycle de vie\ninterne au système.\n"
        }
      ],
      "explanation": "Sous Linux, la commande `ps -aux`\naffiche l'état de chaque processus :\n`R` pour *running* (en exécution),\n`S` pour *sleeping* (en sommeil),\n`D` pour *disk wait* (en attente\nd'entrée-sortie disque), `Z` pour\nzombie."
    },
    {
      "id": "q05",
      "difficulty": 1,
      "skills": [
        "ordonnanceur"
      ],
      "title": "Ordonnanceur",
      "statement": "Quel composant choisit **quel processus**\nreçoit le processeur à chaque instant ?",
      "options": [
        {
          "text": "L'interpréteur de commandes (ou *shell*)",
          "correct": false,
          "feedback": "L'interpréteur de commandes sert\nà lancer des programmes, mais ce\nn'est pas lui qui décide à quel\nmoment chaque processus reçoit le\nprocesseur.\n"
        },
        {
          "text": "Le pilote",
          "correct": false,
          "feedback": "Un pilote est un module qui\npermet au système de communiquer\navec un périphérique matériel\n(carte réseau, imprimante, etc.).\nCe n'est pas son rôle de choisir\nquel processus s'exécute.\n"
        },
        {
          "text": "L'ordonnanceur, qui est un composant du noyau du système d'exploitation",
          "correct": true,
          "feedback": "L'ordonnanceur décide selon\nplusieurs critères : la priorité\ndu processus, l'équité globale\nentre les processus, la latence\nattendue. Sous Linux,\nl'ordonnanceur en place s'appelle\n*Completely Fair Scheduler*.\n"
        },
        {
          "text": "L'utilisateur, à chaque instant",
          "correct": false,
          "feedback": "L'utilisateur peut influencer\nindirectement l'ordonnancement\n(en modifiant la priorité d'un\nprocessus, par exemple), mais il\nne décide pas à chaque instant\nquel processus reçoit le\nprocesseur.\n"
        }
      ],
      "explanation": "Plusieurs stratégies d'ordonnancement\nexistent : le tour de rôle, la\npriorité statique ou dynamique, ou\nencore l'ordonnancement fondé sur la\nlatence. Pour les systèmes\nd'exploitation à contraintes temps\nréel, il faut des garanties strictes\nsur les délais d'exécution."
    },
    {
      "id": "q06",
      "difficulty": 1,
      "skills": [
        "parallelisme"
      ],
      "title": "Parallélisme et concurrence",
      "statement": "Quelle est la différence entre\n**parallélisme** et **concurrence** ?",
      "options": [
        {
          "text": "La concurrence désigne plusieurs tâches en cours logiquement (qui se partagent un même processeur en alternant). Le parallélisme désigne plusieurs tâches s'exécutant réellement en même temps sur des cœurs différents",
          "correct": true,
          "feedback": "Avec un seul cœur, on peut être\nen concurrence (les tâches\nalternent), mais pas en\nparallélisme. Plusieurs cœurs\npermettent un véritable\nparallélisme.\n"
        },
        {
          "text": "La concurrence n'existe pas en informatique",
          "correct": false,
          "feedback": "La concurrence est au contraire\nun concept fondamental, présent\ndans la plupart des systèmes\nd'exploitation modernes.\n"
        },
        {
          "text": "Aucune différence, ce sont deux mots pour la même chose",
          "correct": false,
          "feedback": "La distinction entre les deux\nnotions est importante en\ninformatique, comme expliqué dans\nla bonne réponse.\n"
        },
        {
          "text": "Le parallélisme est toujours plus rapide",
          "correct": false,
          "feedback": "Cette affirmation est trop\nsimpliste. Le parallélisme peut\naccélérer un calcul, mais il\nintroduit un coût de\nsynchronisation et n'est pas\ntoujours bénéfique.\n"
        }
      ],
      "explanation": "Aujourd'hui, les processeurs\nmulti-cœurs offrent un véritable\nparallélisme. En Python, le module\n`multiprocessing` permet du\nparallélisme effectif, alors que le\nmodule `threading` n'offre que de\nla concurrence dans l'implémentation\nde référence du langage."
    },
    {
      "id": "q07",
      "difficulty": 1,
      "skills": [
        "memoire-partagee"
      ],
      "title": "Mémoire partagée entre fils d'exécution",
      "statement": "Pourquoi les fils d'exécution d'un même\nprocessus **partagent-ils** leur mémoire ?",
      "options": [
        {
          "text": "Pour permettre une communication rapide entre fils d'exécution (lire et écrire des variables communes), au prix d'une nécessaire gestion de la synchronisation",
          "correct": true,
          "feedback": "C'est l'avantage majeur des fils\nd'exécution par rapport aux\nprocessus. Cette communication\nrapide est cependant source de\nbugs subtils si l'on ne\nsynchronise pas correctement les\naccès aux variables partagées.\n"
        },
        {
          "text": "Par défaut, ils ne partagent rien",
          "correct": false,
          "feedback": "Le partage de la mémoire est\nprécisément la caractéristique\nqui distingue les fils\nd'exécution des processus.\n"
        },
        {
          "text": "Pour économiser des cœurs de processeur",
          "correct": false,
          "feedback": "Le partage de la mémoire ne\npermet pas d'économiser des\ncœurs. Son intérêt principal\ntient à la rapidité de la\ncommunication entre fils\nd'exécution.\n"
        },
        {
          "text": "Aucune raison particulière",
          "correct": false,
          "feedback": "Le partage de la mémoire entre\nfils d'exécution répond à un\nbesoin précis, comme expliqué\ndans la bonne réponse.\n"
        }
      ],
      "explanation": "C'est un compromis classique entre\nperformance et sécurité. Les fils\nd'exécution communiquent rapidement,\nmais leur partage de mémoire est\nrisqué. Les processus, à l'inverse,\nsont fortement isolés, mais leur\ncommunication est plus coûteuse."
    },
    {
      "id": "q08",
      "difficulty": 1,
      "skills": [
        "signal"
      ],
      "title": "Signal",
      "statement": "Qu'est-ce qu'un **signal** sous Unix ?",
      "options": [
        {
          "text": "Un message textuel envoyé sur un réseau social",
          "correct": false,
          "feedback": "Cette interprétation littérale du\nmot « signal » est sans rapport\navec sa signification en\ninformatique système, où il\ndésigne un mécanisme du système\nd'exploitation.\n"
        },
        {
          "text": "Une instruction du processeur",
          "correct": false,
          "feedback": "Les signaux sont une notion du\nsystème d'exploitation, et non\ndu jeu d'instructions du\nprocesseur.\n"
        },
        {
          "text": "Une notification asynchrone envoyée à un processus pour lui demander une action (terminaison, suspension, reprise…)",
          "correct": true,
          "feedback": "Quelques signaux courants :\n`SIGTERM` (demande polie de\nterminaison), `SIGKILL`\n(terminaison brutale, qui ne\npeut pas être ignorée), `SIGINT`\n(interruption clavier, par\nexemple Ctrl+C), `SIGHUP`\n(rechargement de la\nconfiguration).\n"
        },
        {
          "text": "Un protocole utilisé sur Internet",
          "correct": false,
          "feedback": "Les signaux n'ont aucun rapport\navec les protocoles réseau ; ils\nsont locaux à un système\nd'exploitation.\n"
        }
      ],
      "explanation": "La commande `kill -<signal> <PID>`\nenvoie un signal donné au processus\ndésigné. Par défaut, c'est\n`SIGTERM` (numéro $15$) qui est\nenvoyé. Le signal `SIGKILL`\n(numéro $9$) est plus brutal : le\nprocessus ne peut pas le bloquer ni\nle retarder."
    },
    {
      "id": "q09",
      "difficulty": 1,
      "skills": [
        "exemple-processus"
      ],
      "title": "Lister les processus",
      "statement": "Quelle commande Unix affiche la **liste\ndes processus** en cours d'exécution ?",
      "options": [
        {
          "text": "`ps`, ou `top` pour un suivi en temps réel",
          "correct": true,
          "feedback": "On utilise par exemple `ps aux`\nou `ps -ef` pour obtenir la\nliste complète des processus.\nPour un suivi interactif et\ndynamique, on emploie plutôt\n`top` ou `htop`.\n"
        },
        {
          "text": "`ls`",
          "correct": false,
          "feedback": "La commande `ls` sert à lister\nle contenu d'un répertoire,\nc'est-à-dire les fichiers, pas\nles processus.\n"
        },
        {
          "text": "`cat`",
          "correct": false,
          "feedback": "La commande `cat` sert à\nafficher le contenu d'un\nfichier, et n'a aucun rapport\navec la liste des processus.\n"
        },
        {
          "text": "`grep`",
          "correct": false,
          "feedback": "La commande `grep` sert à\nrechercher un motif dans un\ntexte, mais pas à lister les\nprocessus en cours.\n"
        }
      ],
      "explanation": "Sous Windows, on peut utiliser le\nGestionnaire des tâches\n(`taskmgr.exe`) ou la commande\nPowerShell `Get-Process`. Quel\nque soit le système d'exploitation,\nla liste des processus est\nmaintenue par le noyau."
    },
    {
      "id": "q10",
      "difficulty": 1,
      "skills": [
        "demon"
      ],
      "title": "Démon",
      "statement": "Qu'appelle-t-on un **démon** sur un\nsystème d'exploitation ?",
      "options": [
        {
          "text": "Une commande Unix particulière",
          "correct": false,
          "feedback": "Un démon n'est pas une commande\nmais un processus qui s'exécute\nen arrière-plan.\n"
        },
        {
          "text": "Un programme malveillant",
          "correct": false,
          "feedback": "Le mot « démon » est ici un\nterme technique sans connotation\nnégative. Il désigne un\nprocessus particulier, et non\nun logiciel malveillant.\n"
        },
        {
          "text": "Un processus qui s'exécute en arrière-plan, sans interface utilisateur, généralement lancé au démarrage du système et fournissant un service comme un serveur web, une base de données ou un service de journalisation",
          "correct": true,
          "feedback": "Les noms des démons se\nterminent souvent par la lettre\n« d » : `httpd`, `sshd`,\n`cron`, `systemd`. Ils sont\nvisibles avec la commande `ps`,\nmais aucun terminal ne leur est\nassocié.\n"
        },
        {
          "text": "Un fichier caché du système",
          "correct": false,
          "feedback": "Un démon est un processus, pas\nun fichier. Le mot « caché »\nrenvoie ici à l'absence\nd'interface utilisateur, pas à\nun fichier sur le disque.\n"
        }
      ],
      "explanation": "Sous Linux moderne, `systemd` est\nle processus de démarrage (PID 1)\net gère tous les autres démons.\nSous macOS, ce rôle revient à\n`launchd`. Sous Windows, on parle\nde « services Windows »."
    },
    {
      "id": "q11",
      "difficulty": 2,
      "skills": [
        "course-critique"
      ],
      "title": "Course critique",
      "statement": "Qu'appelle-t-on une **course critique**\n(parfois nommée *race condition*) ?",
      "options": [
        {
          "text": "Une optimisation utilisée par le compilateur",
          "correct": false,
          "feedback": "Une course critique est un\ndéfaut de programmation, pas\nune optimisation.\n"
        },
        {
          "text": "Une compétition sportive informatisée",
          "correct": false,
          "feedback": "Cette interprétation littérale\nest sans rapport avec le sens\ntechnique de l'expression.\n"
        },
        {
          "text": "Un phénomène sans rapport avec les fils d'exécution",
          "correct": false,
          "feedback": "La course critique est\nprécisément un phénomène lié à\nl'exécution concurrente de\nplusieurs fils accédant à des\ndonnées partagées.\n"
        },
        {
          "text": "Un bug qui survient lorsque l'ordre d'exécution de plusieurs fils d'exécution accédant à une même ressource partagée influence le résultat de manière imprévisible",
          "correct": true,
          "feedback": "Exemple typique : deux fils\nd'exécution incrémentent\nsimultanément la même variable.\nSelon l'entrelacement des\nopérations, le résultat varie.\nCes bugs sont particulièrement\ndifficiles à diagnostiquer car\nils sont souvent intermittents.\n"
        }
      ],
      "explanation": "La solution consiste à mettre en\nplace une **synchronisation** des\naccès, par exemple à l'aide de\nverrous, de sémaphores, ou de\ntransactions atomiques. Une\nalternative consiste à éviter\ntoute donnée partagée, par exemple\nen utilisant un échange par files\nde messages."
    },
    {
      "id": "q12",
      "difficulty": 2,
      "skills": [
        "verrou"
      ],
      "title": "Verrou d'exclusion mutuelle",
      "statement": "À quoi sert un **verrou d'exclusion\nmutuelle** ?",
      "options": [
        {
          "text": "À stocker des données partagées",
          "correct": false,
          "feedback": "Un verrou ne stocke pas de\ndonnées, il contrôle l'accès à\ndes données stockées par\nailleurs.\n"
        },
        {
          "text": "À ralentir intentionnellement le programme",
          "correct": false,
          "feedback": "Un verrou peut effectivement\nralentir le programme, mais ce\nn'est pas son objectif. Son\nrôle premier est de garantir la\ncohérence des données\npartagées.\n"
        },
        {
          "text": "À chiffrer les données pour les protéger",
          "correct": false,
          "feedback": "Le chiffrement relève de la\ncryptographie, pas de la\nsynchronisation des fils\nd'exécution.\n"
        },
        {
          "text": "À garantir qu'un seul fil d'exécution à la fois accède à une ressource partagée, ce qui évite les courses critiques",
          "correct": true,
          "feedback": "Le motif classique est le\nsuivant : on acquiert le verrou,\non effectue les opérations\ncritiques, puis on libère le\nverrou. En Python, la syntaxe\n`with verrou:` garantit la\nlibération même en cas\nd'exception, ce qui est plus\nsûr.\n"
        }
      ],
      "explanation": "Plusieurs variantes existent : les\nsémaphores (qui généralisent le\nverrou avec un compteur), les\nverrous lecture-écriture (plusieurs\nlecteurs simultanés autorisés, mais\nun seul écrivain à la fois), et\nles moniteurs (par exemple en\nJava)."
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "interblocage"
      ],
      "title": "Interblocage",
      "statement": "Qu'appelle-t-on un **interblocage** ?",
      "options": [
        {
          "text": "Un arrêt brutal du programme",
          "correct": false,
          "feedback": "Un interblocage n'est pas un\narrêt brutal : les processus\nimpliqués restent actifs, mais\nils sont bloqués en attente\nmutuelle. Aucun ne s'arrête de\nlui-même.\n"
        },
        {
          "text": "Un signal d'erreur émis par le système",
          "correct": false,
          "feedback": "L'interblocage n'émet pas de\nsignal particulier. Au\ncontraire, il se manifeste par\nun blocage silencieux que le\nprogrammeur doit détecter\nlui-même.\n"
        },
        {
          "text": "Un blocage de l'écran",
          "correct": false,
          "feedback": "Le mot peut faire penser à un\ngel de l'affichage, mais le\nsens technique en informatique\nest tout autre. Il s'agit d'un\nblocage logique entre\nprocessus.\n"
        },
        {
          "text": "Une situation dans laquelle plusieurs fils d'exécution ou processus s'attendent mutuellement sans fin, chacun détenant une ressource demandée par un autre",
          "correct": true,
          "feedback": "Exemple : le fil $T_1$ détient\nla ressource $A$ et attend $B$.\nLe fil $T_2$ détient $B$ et\nattend $A$. Aucun ne peut\nprogresser. Quatre conditions,\ndites de Coffman, doivent être\nréunies simultanément pour\nqu'un interblocage se produise.\n"
        }
      ],
      "explanation": "Plusieurs stratégies de prévention\nexistent : ordonner systématiquement\nles acquisitions de ressources\n(toujours $A$ puis $B$),\nutiliser des délais d'attente\n(*timeouts*), détecter les\ninterblocages a posteriori (par\nanalyse des graphes d'attente), ou\nles éviter avec des algorithmes\ndédiés comme l'algorithme du\nbanquier de Dijkstra."
    },
    {
      "id": "q14",
      "difficulty": 2,
      "skills": [
        "ipc"
      ],
      "title": "Communication entre processus",
      "statement": "Comment deux processus **isolés**\npeuvent-ils communiquer entre eux ?",
      "options": [
        {
          "text": "Uniquement par le clavier",
          "correct": false,
          "feedback": "Le clavier permet à un\nutilisateur d'interagir avec\nun programme, mais ce n'est\npas un mécanisme de\ncommunication entre processus.\n"
        },
        {
          "text": "Uniquement via Internet",
          "correct": false,
          "feedback": "Internet permet bien la\ncommunication entre processus\ndistants, mais ce n'est pas le\nseul mécanisme. De nombreux\nprocessus communiquent\nlocalement, sans passer par\nInternet.\n"
        },
        {
          "text": "À l'aide de tubes de communication, de connexions réseau (sockets), de fichiers partagés, d'une mémoire partagée explicite, ou de files de messages",
          "correct": true,
          "feedback": "Tous ces mécanismes sont\nfournis par le système\nd'exploitation. Le tube Unix,\nsymbolisé par la barre\nverticale `|` dans\nl'interpréteur de commandes,\nest l'un des plus simples\nd'usage. Les sockets servent\naux communications réseau, et\nla mémoire partagée privilégie\nla performance.\n"
        },
        {
          "text": "Il leur est impossible de communiquer",
          "correct": false,
          "feedback": "Plusieurs mécanismes\npermettent au contraire à des\nprocessus isolés de\ncommuniquer, comme expliqué\ndans la bonne réponse.\n"
        }
      ],
      "explanation": "Le choix du mécanisme dépend du\nbesoin : un tube convient pour un\nsimple flux ; une connexion\nréseau, pour communiquer à\ndistance ; la mémoire partagée,\npour la performance ; une file de\nmessages, pour découpler le\nproducteur du consommateur."
    },
    {
      "id": "q15",
      "difficulty": 2,
      "skills": [
        "creation-processus"
      ],
      "title": "Création d'un processus",
      "statement": "Sur les systèmes Unix, l'appel système\n`fork` permet de :",
      "options": [
        {
          "text": "Exécuter un nouveau programme depuis le processus courant",
          "correct": false,
          "feedback": "Cette opération correspond à\nl'appel système `exec`, qui\nest souvent combiné avec\n`fork` pour lancer un nouveau\nprogramme dans un nouveau\nprocessus.\n"
        },
        {
          "text": "Terminer immédiatement le processus appelant",
          "correct": false,
          "feedback": "La terminaison d'un processus\nse fait avec un appel système\ncomme `exit`, et non avec\n`fork`.\n"
        },
        {
          "text": "Dupliquer le processus appelant : on obtient un processus parent et un processus enfant, qui partagent au départ le même code et la même mémoire",
          "correct": true,
          "feedback": "Après l'appel à `fork`, on\ndistingue le parent et l'enfant\npar la valeur renvoyée : la\nfonction renvoie $0$ dans le\nprocessus enfant, et le\nnuméro de l'enfant dans le\nprocessus parent. Ce mécanisme\nest fondamental sous Unix.\n"
        },
        {
          "text": "Créer un nouveau fichier sur le disque",
          "correct": false,
          "feedback": "La création d'un fichier\nrelève d'autres appels\nsystème, comme `open` avec\nl'option de création. L'appel\n`fork` concerne les processus,\npas les fichiers.\n"
        }
      ],
      "explanation": "Le motif classique sous Unix est\nl'enchaînement `fork` puis `exec` :\non duplique le processus, puis on\nremplace l'image mémoire de\nl'enfant par un autre programme.\nLe parent peut ensuite continuer\nen parallèle ou attendre la fin\nde l'enfant avec un appel à\n`wait`."
    },
    {
      "id": "q16",
      "difficulty": 2,
      "skills": [
        "zombie"
      ],
      "title": "Processus zombie",
      "statement": "Qu'appelle-t-on un **processus zombie** ?",
      "options": [
        {
          "text": "Un processus terminé dont le code de retour n'a pas encore été récupéré par son parent. Il occupe encore une entrée dans la table des processus",
          "correct": true,
          "feedback": "Cet état apparaît avec la\nlettre `Z` dans la commande\n`ps`. Il est normalement\néphémère. Une accumulation de\nprocessus zombies traduit\nsouvent un bug : le parent ne\nrécupère pas le statut de ses\nenfants. Si le parent meurt,\nle processus de démarrage\n(PID 1) « adopte » les\nprocessus orphelins.\n"
        },
        {
          "text": "Un processus dangereux pour le système",
          "correct": false,
          "feedback": "Le mot « zombie » est ici un\nterme technique sans\nconnotation négative. Il\ndésigne un état particulier\ndans le cycle de vie d'un\nprocessus.\n"
        },
        {
          "text": "Un signal système particulier",
          "correct": false,
          "feedback": "Le zombie n'est pas un signal\nmais un état d'un processus.\n"
        },
        {
          "text": "Un processus pris dans une boucle infinie",
          "correct": false,
          "feedback": "Une boucle infinie correspond\nà un processus qui consomme du\ntemps processeur sans\nterminer. Le zombie est un\nprocessus déjà terminé, dont\nil reste seulement l'entrée\ndans la table des processus.\n"
        }
      ],
      "explanation": "Pour éviter l'apparition de\nprocessus zombies, le parent doit\nappeler `wait` ou `waitpid` après\nla création d'un processus\nenfant. Sans cela, le processus\nenfant reste dans l'état zombie\njusqu'à ce que le parent le\nrécupère explicitement."
    },
    {
      "id": "q17",
      "difficulty": 2,
      "skills": [
        "verrou-global"
      ],
      "title": "Le verrou global de l'interpréteur Python",
      "statement": "Qu'est-ce que le **verrou global de\nl'interpréteur** dans l'implémentation\nprincipale de Python ?",
      "options": [
        {
          "text": "Un module standard de la bibliothèque Python",
          "correct": false,
          "feedback": "Le verrou global de\nl'interpréteur n'est pas un\nmodule Python, mais un\nmécanisme interne de\nl'interpréteur lui-même.\n"
        },
        {
          "text": "Une fonction de la bibliothèque standard",
          "correct": false,
          "feedback": "Le verrou global est un\nmécanisme interne de\nl'interpréteur, pas une\nfonction accessible au\nprogrammeur.\n"
        },
        {
          "text": "Un verrou interne à l'interpréteur qui garantit qu'un seul fil d'exécution Python à la fois exécute du bytecode, ce qui simplifie l'implémentation de l'interpréteur mais limite le parallélisme effectif sur le processeur",
          "correct": true,
          "feedback": "Une conséquence pratique : pour\ndu calcul intensif sur le\nprocesseur, mieux vaut\nutiliser le module\n`multiprocessing` (qui crée de\nvrais processus séparés)\nplutôt que `threading`, à\nmoins que le verrou ne soit\nlibéré pendant les attentes\n(entrées-sorties, par\nexemple).\n"
        },
        {
          "text": "Un éditeur de texte particulier",
          "correct": false,
          "feedback": "Le verrou global est une\nnotion interne au système\nd'exécution de Python, sans\nrapport avec les éditeurs de\ntexte.\n"
        }
      ],
      "explanation": "Ce verrou fait l'objet de débats\ndepuis longtemps. Python 3.13\nintroduit, en option, la\npossibilité de l'enlever. Pour\nles opérations d'entrées-sorties\n(réseau, fichiers), les fils\nd'exécution restent utiles, car\nils libèrent le verrou pendant\nles attentes."
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "priorite"
      ],
      "title": "Priorité d'un processus",
      "statement": "Pourquoi un système d'exploitation\nattribue-t-il des **priorités**\ndifférentes aux processus ?",
      "options": [
        {
          "text": "Aucune raison particulière",
          "correct": false,
          "feedback": "La priorité joue un rôle\nessentiel dans l'allocation\ndu temps processeur, comme\ndétaillé dans la bonne\nréponse.\n"
        },
        {
          "text": "Pour s'assurer que les processus importants (interactifs, système) reçoivent davantage de temps processeur que les processus moins prioritaires (calculs en arrière-plan)",
          "correct": true,
          "feedback": "Une priorité élevée signifie\nplus de temps processeur\nalloué. Sous Linux, la\ncommande `nice` permet de\nrégler cette priorité (de\n$-20$ à $19$ ; un nombre plus\ngrand signifie un processus\nplus « gentil », c'est-à-dire\nmoins prioritaire).\n"
        },
        {
          "text": "Pour des raisons de sécurité",
          "correct": false,
          "feedback": "La sécurité est gérée par les\npermissions et les\nmécanismes d'isolation, pas\npar les priorités, qui\nconcernent l'allocation du\ntemps processeur.\n"
        },
        {
          "text": "Pour faire plaisir aux développeurs",
          "correct": false,
          "feedback": "Les priorités obéissent à des\nconsidérations techniques, pas\nà des préférences\nsubjectives.\n"
        }
      ],
      "explanation": "Les systèmes d'exploitation à\ncontraintes temps réel offrent\ndes garanties strictes sur la\npriorité. Les systèmes\ngénéralistes adoptent une\npolitique « au mieux », tout en\ncherchant à maintenir une équité\nglobale entre les processus."
    },
    {
      "id": "q19",
      "difficulty": 2,
      "skills": [
        "exemples-windows"
      ],
      "title": "Lister les processus sous Windows",
      "statement": "Comment afficher les processus actifs\nsur **Windows** ?",
      "options": [
        {
          "text": "Avec le Gestionnaire des tâches (raccourci Ctrl + Maj + Échap), ou avec la commande PowerShell `Get-Process`",
          "correct": true,
          "feedback": "Le Gestionnaire des tâches\noffre une interface graphique\nriche. En ligne de commande,\non dispose de `tasklist`\n(commande historique) ou de\n`Get-Process` dans\nPowerShell.\n"
        },
        {
          "text": "Avec la commande `ps`",
          "correct": false,
          "feedback": "La commande `ps` est propre\naux systèmes Unix. Elle n'est\npas disponible nativement\nsous Windows.\n"
        },
        {
          "text": "Il est impossible d'observer les processus sous Windows",
          "correct": false,
          "feedback": "Plusieurs outils permettent\nau contraire d'observer les\nprocessus, comme expliqué\ndans la bonne réponse.\n"
        },
        {
          "text": "En éteignant et en rallumant Windows",
          "correct": false,
          "feedback": "Cette plaisanterie n'a pas\nlieu d'être : éteindre le\nsystème ne permet\névidemment pas d'observer\nses processus en cours.\n"
        }
      ],
      "explanation": "Sur tous les systèmes\nd'exploitation modernes, on peut\nobserver les processus, mesurer\nleur consommation de ressources\net les terminer. Les outils\ndiffèrent, mais les fonctions\nproposées sont équivalentes."
    },
    {
      "id": "q20",
      "difficulty": 2,
      "skills": [
        "trace-execution"
      ],
      "title": "Tracer les appels système",
      "statement": "Quelle commande Linux permet de tracer\nles **appels système** effectués par un\nprogramme ?",
      "options": [
        {
          "text": "`ls`",
          "correct": false,
          "feedback": "La commande `ls` liste le\ncontenu d'un répertoire ;\nelle n'a rien à voir avec\nle traçage des appels\nsystème.\n"
        },
        {
          "text": "`grep`",
          "correct": false,
          "feedback": "La commande `grep` sert à\nrechercher un motif dans un\ntexte ; elle n'a aucun\nrapport avec le traçage des\nappels système.\n"
        },
        {
          "text": "`top`",
          "correct": false,
          "feedback": "La commande `top` montre\nl'utilisation des ressources\n(processeur, mémoire) par les\nprocessus, mais elle ne\npermet pas de tracer les\nappels système d'un\nprogramme particulier.\n"
        },
        {
          "text": "`strace`",
          "correct": true,
          "feedback": "La commande `strace\n./mon_programme` affiche\nchaque appel système effectué\npar le programme (`open`,\n`read`, `write`, etc.). C'est\nun outil très utile pour\ncomprendre ce qu'un programme\nfait au niveau du système.\n"
        }
      ],
      "explanation": "Plusieurs variantes existent :\n`ltrace` pour tracer les\nappels aux bibliothèques, `perf`\npour le profilage de\nperformances, ou encore\n`dtrace` sur les systèmes BSD\net macOS. Tous ces outils\npermettent de mieux comprendre\nle comportement effectif d'un\nprogramme."
    },
    {
      "id": "q21",
      "difficulty": 3,
      "skills": [
        "coffman"
      ],
      "title": "Conditions nécessaires à un interblocage",
      "statement": "Quelles sont les **quatre conditions\nnécessaires** pour qu'un interblocage\npuisse se produire (selon Coffman,\n$1971$) ?",
      "options": [
        {
          "text": "La mémoire, le processeur, le disque et le réseau",
          "correct": false,
          "feedback": "Ces éléments sont des types\nde ressources, mais ils ne\nconstituent pas les\nconditions de Coffman, qui\ndécrivent une situation\nd'attente entre processus.\n"
        },
        {
          "text": "Trois conditions seulement suffisent",
          "correct": false,
          "feedback": "Il s'agit bien de quatre\nconditions, qui doivent toutes\nêtre réunies pour qu'un\ninterblocage se produise.\n"
        },
        {
          "text": "Aucune condition particulière",
          "correct": false,
          "feedback": "Un interblocage requiert au\ncontraire la conjonction de\nplusieurs conditions\nprécises, comme expliqué\ndans la bonne réponse.\n"
        },
        {
          "text": "L'exclusion mutuelle, la détention et l'attente, la non-préemption et l'attente circulaire",
          "correct": true,
          "feedback": "Casser une seule de ces\nconditions suffit à éliminer\nle risque d'interblocage.\nPlusieurs stratégies sont\npossibles : autoriser la\npréemption (ce qui casse la\ntroisième condition), ou\nordonner globalement\nl'acquisition des ressources\n(ce qui casse la quatrième).\n"
        }
      ],
      "explanation": "Cette théorie classique permet\nd'analyser tout système\nconcurrent et constitue un\ncontenu classique des cours sur\nles systèmes d'exploitation."
    },
    {
      "id": "q22",
      "difficulty": 3,
      "skills": [
        "reservoir-fils"
      ],
      "title": "Réservoir de fils d'exécution",
      "statement": "Pourquoi utiliser un **réservoir de\nfils d'exécution** plutôt que créer un\nnouveau fil pour chaque tâche ?",
      "options": [
        {
          "text": "Pour économiser sur l'achat du clavier",
          "correct": false,
          "feedback": "Cette interprétation littérale\nn'a aucun rapport avec la\nnotion technique de\nréservoir de fils\nd'exécution.\n"
        },
        {
          "text": "La création d'un fil d'exécution a un coût (allocation de mémoire, mise en place d'un contexte). Un réservoir réutilise un nombre fixe de fils pour de nombreuses tâches, ce qui réduit ce coût et limite le degré de concurrence",
          "correct": true,
          "feedback": "Ce motif de conception est\ncourant dans les serveurs\nweb et dans le calcul\nparallèle. En Python,\n`concurrent.futures.ThreadPoolExecutor`\nfournit un tel réservoir.\nEn Java, on dispose de\n`Executors.newFixedThreadPool(n)`.\n"
        },
        {
          "text": "Il n'y a aucun avantage à utiliser un réservoir",
          "correct": false,
          "feedback": "Le réservoir apporte des\ngains importants en\nperformance et en stabilité,\ncomme expliqué dans la\nbonne réponse.\n"
        },
        {
          "text": "Pour avoir un nombre illimité de fils d'exécution",
          "correct": false,
          "feedback": "Le réservoir vise au\ncontraire à **limiter** le\nnombre de fils d'exécution\nactifs, afin d'éviter la\nsurcharge du système.\n"
        }
      ],
      "explanation": "Une bonne pratique consiste à\ndimensionner la taille du\nréservoir en fonction du nombre\nde cœurs disponibles si la\ncharge est principalement\nprocesseur, ou plus largement si\nla charge est dominée par les\nentrées-sorties (cas où les\nfils sont souvent en attente)."
    },
    {
      "id": "q23",
      "difficulty": 3,
      "skills": [
        "synchronisation-pattern"
      ],
      "title": "Producteurs et consommateurs",
      "statement": "En quoi consiste le motif des\n**producteurs et consommateurs** ?",
      "options": [
        {
          "text": "Une optimisation de la mémoire",
          "correct": false,
          "feedback": "Le motif des producteurs et\nconsommateurs concerne la\nsynchronisation et le\ndécouplage entre tâches, et\nnon l'optimisation de la\nmémoire.\n"
        },
        {
          "text": "Il s'agit d'un patron dans lequel des producteurs déposent des éléments dans une file partagée (avec verrou) et des consommateurs retirent ces éléments pour les traiter. Cela permet de découpler la production de la consommation",
          "correct": true,
          "feedback": "C'est un patron de conception\nfondamental. En Python, la\nclasse `queue.Queue` fournit\nune file synchronisée.\nLorsque la file est pleine,\nle producteur attend ;\nlorsqu'elle est vide, le\nconsommateur attend.\n"
        },
        {
          "text": "Un patron sans intérêt pratique",
          "correct": false,
          "feedback": "Ce motif est au contraire\nomniprésent en programmation\nconcurrente, comme expliqué\ndans la bonne réponse.\n"
        },
        {
          "text": "C'est un motif d'achat-vente",
          "correct": false,
          "feedback": "Ce motif est un patron de\nconception en programmation\nconcurrente, sans rapport\navec le commerce.\n"
        }
      ],
      "explanation": "Plusieurs patrons classiques de\nconcurrence existent :\nproducteurs-consommateurs,\nlecteurs-écrivains, le\nproblème des cinq philosophes,\nla barrière de synchronisation."
    },
    {
      "id": "q24",
      "difficulty": 3,
      "skills": [
        "multiprocess-vs-thread"
      ],
      "title": "Choisir entre multiprocessing et fils d'exécution",
      "statement": "Pour du **calcul intensif** en Python,\nfaut-il préférer les fils d'exécution\nou les processus ?",
      "options": [
        {
          "text": "Les processus, par exemple avec le module `multiprocessing` ou avec `concurrent.futures.ProcessPoolExecutor`, qui contournent le verrou global en utilisant de vrais processus séparés",
          "correct": true,
          "feedback": "Pour des tâches dominées par\nles entrées-sorties (réseau,\nfichiers), les fils\nd'exécution restent\nadaptés. Pour du calcul\nintensif sur le processeur,\nmieux vaut passer par\nplusieurs processus.\n"
        },
        {
          "text": "Uniquement le module asyncio",
          "correct": false,
          "feedback": "Le module `asyncio` est\nconçu pour la concurrence\ndominée par les\nentrées-sorties, et non pour\nle calcul intensif sur le\nprocesseur.\n"
        },
        {
          "text": "Aucune des deux solutions ne convient",
          "correct": false,
          "feedback": "Les deux approches sont\nutiles, chacune dans son\ndomaine, comme expliqué\ndans la bonne réponse.\n"
        },
        {
          "text": "Toujours les fils d'exécution",
          "correct": false,
          "feedback": "En raison du verrou global\nde l'interpréteur dans\nl'implémentation principale\nde Python, les fils\nd'exécution ne parallélisent\npas le calcul effectif sur\nle processeur. Mieux vaut\nutiliser des processus.\n"
        }
      ],
      "explanation": "Compromis : les fils d'exécution\nsont légers et partagent la\nmémoire, mais sont limités par\nle verrou global. Les processus\noffrent un véritable\nparallélisme, mais leur\ncréation et leur communication\nont un coût plus élevé."
    },
    {
      "id": "q25",
      "difficulty": 3,
      "skills": [
        "synthese"
      ],
      "title": "Synthèse",
      "statement": "Parmi les affirmations suivantes sur\nles processus et les fils d'exécution,\nlaquelle est **fausse** ?",
      "options": [
        {
          "text": "Plusieurs fils d'exécution d'un même processus partagent la mémoire",
          "correct": false,
          "feedback": "Cette affirmation est\ncorrecte. C'est même la\ncaractéristique majeure des\nfils d'exécution.\n"
        },
        {
          "text": "Un interblocage requiert la conjonction des quatre conditions de Coffman",
          "correct": false,
          "feedback": "Cette affirmation est\ncorrecte. Casser l'une de\nces quatre conditions suffit\nà éviter l'interblocage.\n"
        },
        {
          "text": "Une course critique est résolue automatiquement par le système d'exploitation",
          "correct": true,
          "feedback": "Cette affirmation est fausse\n(donc c'est la bonne\nréponse). Le système\nd'exploitation ne résout pas\nles courses critiques. Il\nrevient au programmeur\nd'utiliser des mécanismes de\nsynchronisation appropriés\n(verrous, sémaphores, files\nsynchronisées) pour les\néviter.\n"
        },
        {
          "text": "Un processus dispose de sa propre mémoire isolée",
          "correct": false,
          "feedback": "Cette affirmation est\ncorrecte. L'isolation de la\nmémoire est précisément ce\nqui distingue les processus\ndes fils d'exécution.\n"
        }
      ],
      "explanation": "Le programmeur reste\nresponsable de la correction de\nson code concurrent. Le système\nd'exploitation fournit les\noutils, mais c'est à\nl'application d'en faire un\nusage rigoureux pour garantir la\ncohérence des données\npartagées."
    },
    {
      "id": "q26",
      "difficulty": 2,
      "skills": [
        "appel-systeme"
      ],
      "title": "Appel système",
      "statement": "Qu'appelle-t-on un **appel système**\n(*system call*) ?",
      "options": [
        {
          "text": "Une fonction interne au programme\nutilisateur\n",
          "correct": false,
          "feedback": "Erreur : un appel système n'est\npas une fonction interne au\nprogramme. C'est précisément un\nmécanisme par lequel le programme\nsort de son espace propre pour\ndemander un service au noyau.\n"
        },
        {
          "text": "Un appel téléphonique automatisé\n",
          "correct": false,
          "feedback": "Erreur : ce terme n'a aucun\nrapport avec la téléphonie. Il\ndésigne un mécanisme interne du\nsystème d'exploitation.\n"
        },
        {
          "text": "Un protocole de communication\nréseau\n",
          "correct": false,
          "feedback": "Erreur : un appel système est\nlocal au système d'exploitation\nd'une machine. La communication\nréseau peut **passer par** des\nappels système (par exemple\n`socket`), mais elle n'est pas\nelle-même un appel système.\n"
        },
        {
          "text": "Une demande de service adressée\npar un programme au noyau du\nsystème d'exploitation, par\nexemple pour ouvrir un fichier,\nallouer de la mémoire, créer un\nprocessus ou communiquer sur le\nréseau\n",
          "correct": true,
          "feedback": "Bonne réponse : les appels\nsystème sont l'interface entre le\nmode utilisateur (où s'exécutent\nles programmes ordinaires) et le\nmode noyau (où s'exécutent les\nopérations privilégiées). Un\nappel système provoque un\nchangement de contexte vers le\nnoyau, qui exécute la requête\npuis rend la main au programme.\nExemples : `open`, `read`,\n`write`, `fork`, `exec`.\n"
        }
      ],
      "explanation": "Sous Linux, on peut observer les\nappels système d'un programme avec\n`strace`. Les appels système sont\ncoûteux car ils provoquent un\nchangement de contexte. Les\nbibliothèques standard les\nregroupent souvent (par exemple,\nbufferisation des écritures) pour\nréduire leur nombre."
    },
    {
      "id": "q27",
      "difficulty": 3,
      "skills": [
        "memoire-virtuelle"
      ],
      "title": "Mémoire virtuelle",
      "statement": "Pourquoi les systèmes d'exploitation\nmodernes utilisent-ils la **mémoire\nvirtuelle** pour les processus ?",
      "options": [
        {
          "text": "Pour économiser de l'électricité\n",
          "correct": false,
          "feedback": "Erreur : la mémoire virtuelle\nn'a pas pour objectif principal\nla réduction de la consommation\nélectrique. Son rôle premier\nest l'isolation et la flexibilité\nde gestion mémoire.\n"
        },
        {
          "text": "Parce que la mémoire physique\nn'existe plus dans les\nordinateurs modernes\n",
          "correct": false,
          "feedback": "Erreur : la mémoire physique\nexiste bel et bien dans tout\nordinateur ; c'est elle qui\nstocke les données réellement.\nLa mémoire virtuelle est une\nabstraction logicielle au-dessus\nde la mémoire physique.\n"
        },
        {
          "text": "Pour donner à chaque processus\nl'illusion d'un espace mémoire\ncontigu et privé, en mappant les\nadresses virtuelles utilisées par\nle processus sur des adresses\nphysiques réelles ; cela permet\naussi l'isolation entre processus\net la possibilité de gérer plus\nde mémoire que la mémoire physique\ndisponible (via le swap)\n",
          "correct": true,
          "feedback": "Bonne réponse : la mémoire\nvirtuelle est l'un des piliers\ndes systèmes d'exploitation\nmodernes. Avantages : isolation\n(un processus ne peut pas écrire\ndans la mémoire d'un autre),\nflexibilité (la mémoire physique\npeut être fragmentée), illusion\nd'abondance (le système peut\ndéborder sur le disque dur via\nle swap). Inconvénient : un\nléger surcoût lié à la\ntraduction d'adresses, mitigé\npar des composants matériels\ndédiés (TLB).\n"
        },
        {
          "text": "Pour rendre les programmes plus\nrapides à coder\n",
          "correct": false,
          "feedback": "Erreur : la mémoire virtuelle\nn'a pas d'effet direct sur la\nrapidité de développement.\nElle simplifie certains\naspects, mais ce n'est pas son\nmotif principal.\n"
        }
      ],
      "explanation": "Sans mémoire virtuelle, un processus\npourrait lire ou écrire dans la\nmémoire d'un autre processus, ce\nqui poserait des problèmes de\nsécurité majeurs. Aussi, les\nadresses utilisées dans le code\nseraient liées à la position\neffective en mémoire, ce qui\ncompliquerait fortement la\ncompilation et le chargement de\nprogrammes."
    }
  ]
}