Systèmes d'exploitation : trois pièces faciles. Partie 1 : Intro (traduction)

Introduction aux systèmes d'exploitation

Hé Habr ! Je voudrais porter à votre attention une série d'articles-traductions d'une littérature intéressante à mon avis - OSTEP. Ce matériel traite assez en profondeur du travail des systèmes d'exploitation de type Unix, à savoir le travail avec les processus, divers planificateurs, la mémoire et d'autres composants similaires qui composent un système d'exploitation moderne. Vous pouvez voir l'original de tous les matériaux ici ici. Veuillez noter que la traduction a été faite 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:
- original: pages.cs.wisc.edu/~remzi/OSTEP/Homework/homework.html
- original: github.com/remzi-arpacidusseau/ostep-code
- mon adaptation personnelle : github.com/bykvaadm/OS/tree/master/ostep

Vous pouvez également consulter ma chaîne sur télégramme =)

Fonctionnement du programme

Que se passe-t-il lorsqu'un programme est en cours d'exécution ? Un programme en cours d'exécution 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, il reconnaît à quel type appartiennent ces instructions) et les exécute. Il peut s'agir d'ajouter deux nombres, d'accéder à la mémoire, de vérifier une condition, de sauter à une fonction, etc. Après l'exécution d'une instruction, le processeur procède à l'exécution d'une autre. Et donc instruction après 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 des résultats possibles, d'exécuter des instructions simultanément et des astuces similaires.

Modèle de calcul de Von Neumann

La forme de travail simplifiée que nous avons décrite est similaire au modèle de calcul de Von Neumann. Von Neumann est l'un des pionniers des systèmes informatiques, il est aussi l'un des auteurs de la théorie des jeux. Pendant que le programme est en cours d'exécution, de nombreux autres événements ont lieu, de nombreux autres processus et logiques tierces fonctionnent, dont le but principal est de simplifier le lancement, le fonctionnement et la maintenance du système.
Il existe un ensemble de logiciels qui sont chargés de rendre les programmes faciles à exécuter (ou même de permettre à plusieurs programmes de s'exécuter en même temps), qui permettent aux programmes de partager la même mémoire et de communiquer avec différents appareils. Un tel ensemble de logiciels (logiciels) est essentiellement appelé le système d'exploitation et ses tâches comprennent la surveillance du fonctionnement correct et efficace du système, ainsi que la garantie de la facilité de gestion de ce système.

Système d'exploitation

Un système d'exploitation, abrégé en OS, est un ensemble de programmes interdépendants conçus pour gérer les ressources informatiques et organiser l'interaction de l'utilisateur avec un ordinateur..
Le système d'exploitation atteint son efficacité en premier lieu, grâce à la technique la plus importante - la technique 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 de lui-même. Par conséquent, pour une compréhension générale, vous pouvez comparer très grossièrement le système d'exploitation avec une machine virtuelle.
Afin de permettre aux utilisateurs de donner des commandes au système d'exploitation et ainsi d'utiliser les capacités de la machine virtuelle (telles que l'exécution d'un programme, l'allocation de mémoire, l'accès à un fichier, etc.), le système d'exploitation fournit une interface appelée API (interface de programmation d'application) et vers laquelle vous pouvez passer des appels (appel). Un système d'exploitation typique permet d'effectuer des centaines d'appels système.
Enfin, puisque la virtualisation permet à plusieurs programmes de s'exécuter (partageant ainsi le CPU), et d'accéder simultanément à leurs instructions et données (partageant ainsi la mémoire), et d'accéder aux disques (partageant ainsi les périphériques d'E/S), le système d'exploitation est aussi appelé un 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, le faire efficacement, honnêtement, ou vice versa, selon la tâche pour laquelle ce système d'exploitation est conçu.

Virtualisation du processeur

Considérez le programme suivant :
(https://www.youtube.com/watch?v=zDwT5fUcki4&feature=youtu.be)

Systèmes d'exploitation : trois pièces faciles. Partie 1 : Intro (traduction)

Il n'effectue aucune action spéciale, en fait, il ne fait qu'appeler une fonction tourner(), dont la tâche est de faire défiler le contrôle du temps et de revenir après qu'une seconde se soit écoulée. Ainsi, il répète indéfiniment la chaîne que l'utilisateur a passée en argument.
Exécutons ce programme et donnons-lui le caractère "A" comme argument. Le résultat n'est pas particulièrement intéressant - le système exécute simplement un programme qui affiche périodiquement le caractère "A".
Essayons maintenant l'option lorsque de nombreuses instances du même programme sont en cours d'exécution, mais produisent des lettres différentes pour le rendre plus clair. Dans ce cas, le résultat sera quelque peu différent. Malgré le fait que nous ayons un processeur, le programme est exécuté simultanément. Comment ça se passe ? 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 que le système dispose de plusieurs processeurs virtuels, transformant un seul processeur physique en un nombre théoriquement infini et permettant ainsi à des programmes apparemment exécutés simultanément. Cette illusion s'appelle Virtualisation du processeur.
Cette image soulève de nombreuses questions, par exemple, si plusieurs programmes veulent s'exécuter en même temps, lequel sera lancé ? Les « politiques » de l'OS sont responsables de cette question. Les stratégies sont utilisées à de nombreux endroits dans le système d'exploitation et répondent à des questions comme celle-ci, et sont 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

Intéressons-nous maintenant à la mémoire. Le modèle physique de la mémoire dans les systèmes modernes est représenté par un tableau d'octets.. Pour lire à partir de la mémoire, vous devez spécifier adresse cellulairepour y accéder. Pour écrire ou mettre à jour des données, vous devez également spécifier les données et l'adresse de la cellule où les écrire.
La mémoire est consultée en permanence pendant l'exécution du programme. Un programme stocke toute sa structure de données en mémoire et y accède en exécutant diverses instructions. Les instructions, quant à elles, sont également stockées en mémoire, de sorte qu'il est également accessible pour chaque demande de l'instruction suivante.

appel malloc()

Considérez le programme suivant, qui alloue une région de mémoire en utilisant l'appel malloc () (https://youtu.be/jnlKRnoT1m0) :

Systèmes d'exploitation : trois pièces faciles. Partie 1 : Intro (traduction)

Le programme fait plusieurs choses. Tout d'abord, il alloue de la mémoire (ligne 7), puis imprime l'adresse de la cellule allouée (ligne 9), écrit zéro dans le premier emplacement de la mémoire allouée. Ensuite, le programme entre dans une boucle dans laquelle il incrémente la valeur stockée en mémoire à l'adresse dans la variable "p". Il imprime également l'ID 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 tomberons sur un résultat intéressant : dans le premier cas, si vous ne faites rien et que vous vous contentez de lancer plusieurs copies, alors les adresses seront différentes. Mais cela ne rentre pas dans notre théorie ! Correct, car les distributions modernes ont la randomisation de la mémoire activée par défaut. S'il est désactivé, nous obtenons le résultat attendu - les adresses mémoire de deux programmes exécutés simultanément correspondront.

Systèmes d'exploitation : trois pièces faciles. Partie 1 : Intro (traduction)

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 mappé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 rien les autres, et il semble à chaque programme qu'il a sa propre mémoire physique, qui lui est entièrement donnée. 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 des sujets importants dans les systèmes d'exploitation est - cohérence. Ce terme est utilisé pour parler de problèmes dans le système qui peuvent survenir lorsque vous travaillez avec plusieurs éléments en même temps dans le même programme. Des problèmes de cohérence surviennent même au sein du système d'exploitation lui-même. Dans les exemples précédents de virtualisation de la mémoire et du processeur, nous avons réalisé que le système d'exploitation gère plusieurs choses en même temps - il démarre le premier processus, puis le second, et ainsi de suite. 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 :

Systèmes d'exploitation : trois pièces faciles. Partie 1 : Intro (traduction)

Le programme de la fonction main crée deux threads en utilisant 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 aux côtés d'autres fonctions, avec clairement plus d'une fonction s'exécutant en même temps. Dans cet exemple, chaque thread démarre et exécute la fonction worker() qui à son tour incrémente simplement la variable,.

Exécutons ce programme avec un argument de 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 un ordre de grandeur plus de répétitions.

Systèmes d'exploitation : trois pièces faciles. Partie 1 : Intro (traduction)

En entrant un nombre, par exemple, 100000, nous nous attendons à voir la sortie comme le nombre 200000. Cependant, si nous exécutons le nombre 100000 plusieurs fois, non seulement nous ne verrons pas la bonne réponse, mais nous obtiendrons é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 exécutées de manière atomique (toutes en même temps), des choses étranges comme celle-ci peuvent se produire. Ce problème est appelé en programmation condition de course. Lorsque des forces inconnues à un moment inconnu peuvent affecter les performances de l'une de vos opérations.

Source: habr.com

Ajouter un commentaire