Introduction aux systèmes d'exploitation
Bonjour, Habr! Je veux attirer votre attention sur une série d'articles-traductions d'une littérature intéressante à mon avis - OSTEP. Cet article décrit assez en profondeur le travail des systèmes d'exploitation de type Unix, à savoir le travail avec les processus, les différents planificateurs, la mémoire et d'autres composants similaires qui composent le système d'exploitation moderne. L'original de tous les matériaux que vous pouvez voir
ici . Veuillez noter que la traduction a été effectuée de manière non professionnelle (assez librement), mais j'espère avoir conservé le sens général.
Les travaux de laboratoire sur ce sujet peuvent être trouvés ici:
Autres parties:
Et vous pouvez regarder ma chaîne en
télégramme =)
Travail de programme
Que se passe-t-il lorsqu'un programme fonctionne? L'exécution de programmes fait une chose simple: il exécute des instructions. Chaque seconde, des millions voire des milliards d'instructions sont extraites par le processeur de la RAM, à son tour, il les décode (par exemple, reconnaît à quel type appartiennent ces instructions) et les exécute. Cela peut être l'ajout de deux nombres, l'accès à la mémoire, la vérification des conditions, le passage aux fonctions, etc. Après l'achèvement d'une instruction, le processeur procède à l'exécution d'une autre. Et donc instruction par instruction, elles sont exécutées jusqu'à la fin du programme.
Cet exemple est naturellement considéré comme simplifié - en fait, pour accélérer le processeur, le matériel moderne vous permet d'exécuter des instructions hors tour, de calculer les résultats possibles, de suivre les instructions en même temps et des astuces similaires.
Modèle informatique Von Neumann
La forme de travail simplifiée que nous décrivons est similaire au modèle de calcul de Von Neumann.
Von Neumann est l'un des pionniers des systèmes informatiques; il est également l'un des auteurs de la théorie des jeux . Pendant l'exécution du programme, un tas d'autres événements se produisent, de nombreux autres processus et travaux de logique tiers, dont le principal objectif est de simplifier le lancement, le fonctionnement et la maintenance du système.
Il existe un ensemble de logiciels qui est responsable de la simplicité d'exécution des programmes (ou même vous permet d'exécuter plusieurs programmes en même temps), il permet aux programmes de partager la même mémoire, ainsi que d'interagir avec différents appareils. Un tel ensemble de logiciels (logiciels) est essentiellement appelé système d'exploitation et ses tâches comprennent la surveillance du bon fonctionnement et de l'efficacité du système, ainsi que la facilité de gestion de ce système.
Système d'exploitation
Un système d'exploitation, abréviation de OS, est un complexe de programmes interconnectés conçus pour gérer les ressources informatiques et organiser l'interaction d'un utilisateur avec un ordinateur .
L'OS atteint son efficacité principalement grâce à la technique la plus importante - la technique de
virtualisation . Le système d'exploitation interagit avec une ressource physique (processeur, mémoire, disque, etc.) et la transforme en une forme plus générale, plus puissante et plus facile à utiliser. Par conséquent, pour une compréhension générale, vous pouvez comparer très approximativement le système d'exploitation avec une machine virtuelle.
Afin de permettre aux utilisateurs de donner des instructions au système d'exploitation et ainsi utiliser les capacités d'une machine virtuelle (comme: lancer un programme, allouer de la mémoire, accéder à un fichier, etc.), le système d'exploitation fournit une interface appelée
API (interface de programmation d'application) et à laquelle Vous pouvez passer des appels. Un système d'exploitation typique permet de faire des centaines d'appels système.
Et enfin, puisque la virtualisation permet à de nombreux programmes de fonctionner (partageant ainsi le CPU), et en même temps d'avoir accès à leurs instructions et données (partageant ainsi la mémoire), ainsi que d'accéder aux disques (partageant ainsi les périphériques d'E / S ), le système d'exploitation est également appelé gestionnaire de ressources. Chaque processeur, disque et mémoire est une ressource du système et donc l'un des rôles du système d'exploitation devient la tâche de gérer ces ressources, de le faire efficacement, honnêtement ou, inversement, selon la tâche pour laquelle ce système d'exploitation est conçu.
Virtualisation CPU
Considérez le programme suivant:
(https://www.youtube.com/watch?v=zDwT5fUcki4)

Il n'effectue aucune action spéciale, en fait il ne fait qu'appeler la fonction
spin (), dont la tâche est de faire défiler le temps et de revenir après une seconde. Ainsi, il répète sans fin la chaîne que l'utilisateur a passée en argument.
Exécutez ce programme et passez-lui le symbole «A» comme argument. Le résultat n'est pas très intéressant - le système exécute simplement un programme qui affiche périodiquement le symbole «A».
Essayons maintenant l'option lorsque de nombreuses instances du même programme sont en cours d'exécution, mais en affichant différentes lettres, afin que cela soit plus compréhensible. Dans ce cas, le résultat sera légèrement différent. Malgré le fait que nous ayons un processeur, le programme s'exécute simultanément. Comment cela se produit-il? Mais il s'avère que le système d'exploitation, non sans l'aide de capacités matérielles, crée une illusion. L'illusion qu'il y a plusieurs processeurs virtuels dans le système, transformant un processeur physique en un nombre théoriquement infini et permettant ainsi aux programmes d'apparaître pour être exécutés simultanément. Une telle illusion est appelée
Virtualisation CPU .
Une telle image soulève de nombreuses questions, par exemple, si plusieurs programmes veulent démarrer simultanément, lequel sera lancé? Les "politiques" de l'OS sont responsables de cette question. Les politiques sont utilisées dans de nombreux endroits du système d'exploitation et répondent à des questions similaires, et sont également les mécanismes de base que le système d'exploitation implémente. D'où le rôle de l'OS en tant que gestionnaire de ressources.
Virtualisation de la mémoire
Regardons maintenant la mémoire.
Le modèle de mémoire physique dans les systèmes modernes est représenté comme un tableau d'octets . Pour lire de la mémoire, vous devez spécifier l'
adresse de la cellule afin d'y accéder. Pour enregistrer ou mettre à jour des données, vous devez également spécifier les données et l'adresse de la cellule où les écrire.
Les accès à la mémoire se produisent constamment pendant le fonctionnement du programme. Un programme stocke en mémoire toute sa structure de données et y accède en suivant diverses instructions. Les instructions, quant à elles, sont également stockées en mémoire, de sorte qu'il est également accessible pour chaque demande à l'instruction suivante.
Appeler malloc ()
Considérez le programme suivant qui alloue une région de mémoire à l'aide de l'appel
malloc () (https://youtu.be/jnlKRnoT1m0):

Le programme fait quelques choses. Tout d'abord, il alloue une certaine quantité de mémoire (ligne 7), puis affiche l'adresse de la cellule sélectionnée (ligne 9), écrit zéro dans le premier emplacement de la mémoire allouée. Ensuite, le programme entre dans un cycle dans lequel il incrémente la valeur enregistrée en mémoire à l'adresse de la variable "p". Il affiche également l'identifiant de processus de lui-même.
L'ID de processus est unique pour chaque processus en cours d'exécution . Après avoir lancé plusieurs copies, nous arriverons à un résultat intéressant: dans le premier cas, si vous ne faites rien et commencez simplement plusieurs copies, les adresses seront différentes. Mais cela ne relève pas de notre théorie! C'est vrai, car dans les distributions modernes, la fonction de randomisation de la mémoire est activée par défaut. Si vous le désactivez, nous obtenons le résultat escompté - les adresses mémoire de deux programmes exécutés simultanément coïncideront.
En conséquence, il s'avère que deux programmes indépendants fonctionnent avec leurs propres espaces d'adressage privés, qui à leur tour sont affichés par le système d'exploitation dans la mémoire physique . Par conséquent, l'utilisation d'adresses mémoire dans un programme n'affectera en aucun cas les autres, et il semble à chaque programme qu'il possède sa propre mémoire physique, qui est entièrement à sa disposition. La réalité, cependant, est que la mémoire physique est une ressource partagée gérée par le système d'exploitation.
Cohérence
Un autre sujet important dans les systèmes d'exploitation est la
cohérence . Ce terme est utilisé lorsqu'il s'agit de problèmes dans le système qui peuvent survenir lorsque vous travaillez avec plusieurs choses en même temps dans le même programme. Des problèmes de cohérence se posent même dans le système d'exploitation lui-même. Dans les exemples précédents avec la virtualisation de la mémoire et du processeur, nous avons réalisé que le système d'exploitation gère beaucoup de choses en même temps - il démarre le premier processus, puis le second, etc. Il s'est avéré que ce comportement peut entraîner certains problèmes. Ainsi, par exemple, les programmes multithreads modernes rencontrent de telles difficultés.
Considérez le programme suivant:

Le programme de la fonction principale crée deux threads à l'aide de l'appel
Pthread_create () . Dans cet exemple, un thread peut être considéré comme une fonction s'exécutant dans le même espace mémoire à côté d'autres fonctions, et le nombre de fonctions lancées simultanément est clairement supérieur à une. Dans cet exemple, chaque thread démarre et exécute la fonction
worker () ,
qui à son tour incrémente simplement la variable ,.Exécutez ce programme avec l'argument 1000. Comme vous l'avez peut-être deviné, le résultat devrait être 2000, car chaque thread a incrémenté la variable 1000 fois. Cependant, tout n'est pas si simple. Essayons d'exécuter le programme avec le nombre de répétitions un ordre de grandeur de plus.

En entrant un nombre, par exemple, 100 000, nous nous attendons à voir 200 000 sur la sortie. Cependant, en exécutant le nombre 100 000 plusieurs fois, nous verrons non seulement la bonne réponse, mais également différentes réponses incorrectes. La réponse réside dans le fait que pour augmenter le nombre, trois opérations sont nécessaires - extraire le nombre de la mémoire, incrémenter puis réécrire le nombre. Étant donné que toutes ces instructions ne sont pas implémentées de manière atomique (toutes en même temps), de telles choses étranges peuvent se produire. Ce problème est appelé programmation des
conditions de concurrence -
condition de concurrence . Quand des forces inconnues à un moment inconnu peuvent affecter les performances de vos opérations.