Ministère des transports de la Fédération de Russie

Agence fédérale des transports ferroviaires

GOU VPO "DVGUPS"

Département : "Technologies et systèmes de l'information"

COURS DE TRAVAIL

sur le thème : "Sous-système de gestion des processus"

Complété par : Sholkov I.D.

groupe 230

Vérifié par: Reshetnikova O.V.

Khabarovsk 2010

Introduction

1. Descriptif du programme

1.1 Fonctionnalité

1.2 Moyens techniques utilisés pour créer le programme

1.3 Multithreading et multitraitement

1.4 Priorités des threads et des processus

1.5 Méthodes de synchronisation des threads

1.3 Structure logique du programme

2. Guide de l'utilisateur pour travailler avec le programme

2.1 Informations générales et objectif du programme

2.2 Interface graphique

2.3 Travailler avec le programme

2.4 Fonctionnalités clés de ProcessManager

Conclusion

Bibliographie

C # prend en charge l'exécution de code parallèle via le multithreading. Un thread est un chemin d'exécution indépendant capable de s'exécuter simultanément avec d'autres threads.

Un programme C# démarre comme un thread unique créé automatiquement par le CLR et le système d'exploitation (le thread "maître") et devient multithread en créant des threads supplémentaires.

Le multithreading est géré par le planificateur de threads, une fonction que le CLR délègue généralement au système d'exploitation. Le planificateur de threads garantit que les threads actifs reçoivent un temps d'exécution approprié et que les threads en attente ou bloqués, tels que l'attente d'un verrou exclusif ou d'une entrée utilisateur, ne consomment pas de temps CPU.

Sur les ordinateurs monoprocesseurs, le planificateur de threads utilise le découpage temporel, c'est-à-dire une commutation rapide entre l'exécution de chacun des threads actifs. Cela conduit à un comportement imprévisible, comme dans le tout premier exemple, où chaque séquence de caractères 'X' et 'Y' correspond à une tranche de temps allouée au thread. Dans Windows XP, la valeur de tranche de temps typique - des dizaines de millisecondes - est choisie pour être beaucoup plus grande que le coût CPU d'un changement de contexte entre les threads (plusieurs microsecondes).

Sur les ordinateurs multiprocesseurs, le multithreading est implémenté comme un mélange de découpage temporel et de véritable parallélisme, avec différents threads exécutant du code sur différents processeurs. Le besoin de trancher le temps demeure, car le système d'exploitation doit gérer à la fois ses propres threads et ceux des autres applications.

Un thread est dit préempté lorsque son exécution est suspendue en raison de facteurs externes tels que le découpage temporel. Dans la plupart des cas, un thread n'a aucun contrôle sur le moment et l'endroit où il sera préempté.

Tous les threads d'une application sont logiquement contenus dans un processus, le module du système d'exploitation dans lequel l'application s'exécute.

À certains égards, les threads et les processus sont similaires, par exemple, le temps est partagé entre les processus exécutés sur le même ordinateur, tout comme il est partagé entre les threads de la même application C#. La principale différence est que les processus sont complètement isolés les uns des autres. Les threads partagent la mémoire (le tas) avec d'autres threads de la même application. Cela permet à un thread de fournir des données en arrière-plan et à un autre de montrer ces données à mesure qu'elles arrivent.

La propriété Priority détermine la durée d'exécution d'un thread par rapport aux autres threads du même processus. Il existe 5 niveaux de priorité de thread : enum ThreadPriority ( Lowest, BelowNormal, Normal, AboveNormal, Highest )

La valeur de priorité devient significative lorsque plusieurs threads s'exécutent en même temps.

Définir la priorité des threads au maximum ne signifie pas un fonctionnement en temps réel, car il existe toujours une priorité de processus d'application. Pour travailler en temps réel, vous devez utiliser la classe Process de l'espace de noms System.Diagnostics pour augmenter la priorité du processus.

De ProcessPriorityClass.High une étape à la priorité de processus la plus élevée - Temps réel. En définissant la priorité du processus sur Temps réel, vous indiquez au système d'exploitation que vous souhaitez que votre processus ne soit jamais devancé. Si votre programme entre accidentellement dans une boucle infinie, le système d'exploitation peut être complètement bloqué. Dans ce cas, seul le bouton d'alimentation peut vous sauver. Pour cette raison, ProcessPriorityClass.High est considéré comme la priorité de processus utilisable la plus élevée.

Si une application en temps réel a une interface utilisateur, il n'est peut-être pas souhaitable d'augmenter la priorité de son processus, car la mise à jour de l'écran consommera trop de temps CPU, ce qui ralentira l'ensemble de l'ordinateur, surtout si l'interface utilisateur est suffisamment complexe.

L'instruction de verrouillage (alias Monitor.Enter/Monitor.Exit) est un exemple de constructions de synchronisation de threads. Le verrouillage est le moyen le plus adapté pour organiser l'accès exclusif à une ressource ou à une section de code, mais il existe des tâches de synchronisation (comme signaler le début du travail à un thread en attente) pour lesquelles le verrouillage ne sera pas le moyen le plus adéquat et le plus pratique.

L'API Win32 possède un riche ensemble de constructions de synchronisation, et elles sont disponibles dans le .NET Framework en tant que classes EventWaitHandle, Mutex et Semaphore. Certains sont plus pratiques que d'autres : Mutex, par exemple, duplique en grande partie les capacités de verrouillage, tandis que EventWaitHandle fournit des capacités de signalisation uniques.

Les trois classes sont basées sur la classe abstraite WaitHandle, mais leur comportement est assez différent. L'une des caractéristiques communes est la capacité de dénomination, qui permet de travailler avec des threads non seulement d'un, mais également de différents processus.

EventWaitHandle a deux classes dérivées, AutoResetEvent et ManualResetEvent (qui n'ont rien à voir avec les événements et délégués C#). Les deux classes ont accès à toutes les fonctionnalités de la classe de base, la seule différence est que le constructeur de la classe de base est appelé avec des paramètres différents.

En termes de performances, tous les WaitHandles s'exécutent généralement en quelques microsecondes. Cela importe rarement compte tenu du contexte dans lequel ils sont appliqués.

AutoResetEvent est la classe WaitHandle la plus couramment utilisée et la construction de synchronisation principale, avec lock.

AutoResetEvent est très similaire à un tourniquet - un ticket permet à une personne d'entrer. Le préfixe "auto" dans le nom fait référence au fait qu'un tourniquet ouvert se ferme automatiquement ou "se réinitialise" après avoir permis à quelqu'un de passer. Le thread est bloqué au tourniquet en appelant WaitOne (attendre (attendre) à ce (un) tourniquet jusqu'à ce qu'il s'ouvre), et le ticket est inséré en appelant la méthode Set. Si plusieurs threads appellent WaitOne, une file d'attente se forme derrière le tourniquet. Le ticket peut "insérer" n'importe quel thread - en d'autres termes, tout thread (non bloquant) ayant accès à l'objet AutoResetEvent peut appeler Set pour ignorer un thread bloqué.

Si Set est appelé lorsqu'il n'y a pas de threads en attente, le handle restera ouvert jusqu'à ce qu'un thread appelle WaitOne. Cette fonctionnalité permet d'éviter une course entre le fil s'approchant du tourniquet et le fil insérant le ticket ("oups, le ticket a été inséré une microseconde en avance, désolé, mais il va falloir patienter encore !"). Cependant, plusieurs appels à Set pour un tourniquet gratuit ne permettent pas à toute une foule de passer à la fois - une seule personne pourra passer, tous les autres billets seront gaspillés.

WaitOne prend un paramètre de délai d'attente facultatif - la méthode renvoie false si l'attente se termine par un délai d'attente et non par un signal. WaitOne peut également être entraîné à quitter le contexte de synchronisation actuel pour continuer à attendre (si le mode de blocage automatique est utilisé) afin d'éviter un blocage excessif.

La méthode de réinitialisation garantit qu'un tourniquet ouvert est fermé sans attente ni blocage.

Un AutoResetEvent peut être créé de deux manières. D'abord, avec son constructeur : EventWaitHandle wh = new AutoResetEvent(false);

Le système de gestion des tâches assure leur passage dans l'ordinateur. Selon l'état du processus, il doit allouer l'une ou l'autre ressource. Par exemple, un nouveau processus doit être placé en mémoire en lui allouant un espace d'adressage ; inclure dans la liste des tâches en concurrence pour le temps CPU.

L'un des principaux sous-systèmes d'un système d'exploitation multiprogramme qui affecte directement le fonctionnement d'un ordinateur est sous-système de gestion des processus et des threads. Il est engagé dans leur création et leur destruction, et distribue également le temps processeur entre les processus et les threads qui existent simultanément dans le système.

Lorsque plusieurs tâches s'exécutent dans le système en même temps, bien que les threads soient créés et exécutés de manière asynchrone, ils peuvent avoir besoin d'interagir, par exemple, lors de l'échange de données. Par conséquent, la synchronisation des threads est l'une des fonctions importantes du sous-système de gestion des processus et des threads.

L'interaction entre les processus est effectuée à l'aide de variables partagées et d'opérations de base spéciales appelées primitives.

Le sous-système de gestion des processus et des threads a la capacité d'effectuer les opérations suivantes sur les processus :

– création (spawning)/destruction d'un processus ;

– suspension/reprise du processus ;

– blocage/réactivation du processus ;

– démarrage du processus ;

– changement de priorité de processus;

Le sous-système de gestion des processus et des threads est chargé de fournir aux processus les ressources nécessaires. Le système d'exploitation conserve des structures d'informations spéciales en mémoire, dans lesquelles il enregistre les ressources allouées à chaque processus. Une ressource peut être affectée à un processus pour un usage exclusif ou partagée avec d'autres processus. Certaines des ressources sont allouées au processus lors de sa création, et certaines sont allouées dynamiquement par des requêtes lors de l'exécution. Les ressources peuvent être affectées à un processus pour toute sa durée de vie ou seulement pour une période spécifique. Lors de l'exécution de ces fonctions, le sous-système de contrôle de processus interagit avec d'autres sous-systèmes du système d'exploitation responsables de la gestion des ressources, tels que le sous-système de gestion de la mémoire, le sous-système d'E / S, le système de fichiers.

1. Créer et supprimer des processus et des threads

Créer un processus, c'est d'abord créer descripteur de processus, qui est une ou plusieurs structures d'informations contenant toutes les informations sur le processus dont le système d'exploitation a besoin pour le gérer. Cette question a été examinée en détail plus tôt, maintenant nous rappelons seulement que ces informations peuvent inclure, par exemple, l'identifiant du processus, des données sur l'emplacement dans la mémoire du module exécutable, le degré de privilège du processus (priorité et droits d'accès) , etc.

La création d'un processus implique le chargement des codes et des données du programme exécutable du processus à partir du disque dans la RAM. Dans ce cas, le sous-système de gestion de processus interagit avec le sous-système de gestion de mémoire et le système de fichiers. Dans un système multithread, lorsqu'un processus est créé, le système d'exploitation crée au moins un thread d'exécution pour chaque processus. Lors de la création d'un thread, tout comme lors de la création d'un processus, le système d'exploitation génère une structure d'informations spéciale - un descripteur de thread, qui contient l'identifiant du thread, des données sur les droits d'accès et la priorité, l'état du thread, etc. Une fois créé, un thread (ou processus) est dans un état prêt à fonctionner (ou dans un état inactif dans le cas d'un système d'exploitation spécialisé).

La création et la suppression de tâches sont effectuées sur les demandes appropriées des utilisateurs ou d'autres tâches. Une tâche peut générer une nouvelle tâche - dans de nombreux systèmes, un thread peut contacter le système d'exploitation avec une demande de création d'un soi-disant. flux descendants. La tâche parent est appelée "ancêtre", "parent" et la tâche enfant est appelée "enfant" ou "tâche enfant". Un "ancêtre" peut suspendre ou supprimer sa tâche enfant, tandis qu'un "enfant" ne peut pas contrôler "l'ancêtre".

Dans différents systèmes d'exploitation, les relations entre les threads enfants et leurs parents sont construites différemment. Dans certains systèmes d'exploitation, leur exécution est synchronisée (après l'achèvement du thread parent, tous ses descendants sont supprimés de l'exécution), dans d'autres, les descendants sont exécutés de manière asynchrone par rapport au thread parent.

Une fois le processus terminé, le système d'exploitation "nettoie les traces" de son séjour dans le système - il ferme tous les fichiers avec lesquels le processus a travaillé, libère les zones de RAM allouées aux codes, aux données et aux structures d'informations système du processus . Les files d'attente et les listes de ressources du système d'exploitation contenant des références au processus en cours d'arrêt sont corrigées.

2. Planification et répartition des processus et des threads

La stratégie de planification détermine quels processus sont sélectionnés pour être exécutés afin d'atteindre l'objectif. Les stratégies peuvent être différentes, par exemple :

– si possible, terminer les calculs dans le même ordre dans lequel ils ont commencé ;

– privilégier les processus courts ;

– fournir à tous les utilisateurs (tâches utilisateur) les mêmes services, y compris le même temps d'attente.

Au cours de la vie d'un processus, l'exécution de ses threads peut être interrompue et poursuivie à plusieurs reprises.

Le passage de l'exécution d'un thread à un autre s'effectue à la suite de Planification et expéditeur.

Planification Les flux sont exécutés sur la base des informations stockées dans les descripteurs de processus et de thread. Lors de la planification, la priorité des threads, leur temps d'attente dans la file d'attente, le temps d'exécution cumulé, l'intensité de l'accès aux E/S et d'autres facteurs peuvent être pris en compte. Le système d'exploitation planifie l'exécution des threads, qu'ils appartiennent au même processus ou à des processus différents. La planification est comprise comme la tâche de sélectionner un ensemble de processus tel qu'ils entrent en conflit le moins possible pendant l'exécution et utilisent le système informatique aussi efficacement que possible.

Dans diverses sources d'information, il existe différentes interprétations des concepts de "planification" et de "répartition". Ainsi, certains auteurs divisent la planification en long terme (global) et court terme (dynamique, c'est-à-dire la distribution la plus efficace actuelle), et cette dernière est appelée dispatching. Selon d'autres sources, la planification est comprise comme la mise en œuvre de la décision prise au stade de la planification. Nous nous en tiendrons à cette option.

Planification comprend deux tâches :

déterminer un instant pour changer le fil actif ;

sélection pour l'exécution d'un thread dans la file d'attente des threads prêts.

Il existe de nombreux algorithmes d'ordonnancement qui résolvent ces problèmes de différentes manières. Ce sont les fonctionnalités de planification qui déterminent les spécificités du système d'exploitation. Regardons-les un peu plus tard.

Dans la plupart des systèmes d'exploitation, la planification est effectuée dynamiquement, c'est à dire. les décisions sont prises pendant le travail sur la base d'une analyse de la situation actuelle. Les threads et les processus apparaissent à des moments aléatoires et se terminent de manière imprévisible.

Statique le type d'ordonnancement peut être utilisé dans des systèmes spécialisés dans lesquels l'ensemble des tâches exécutées simultanément est défini à l'avance (systèmes temps réel). L'ordonnanceur génère un ordonnancement basé sur la connaissance des caractéristiques d'un ensemble de tâches. Ce calendrier est ensuite utilisé par le système d'exploitation pour la planification.

expéditeur est de mettre en œuvre la solution trouvée à la suite de la planification, c'est-à-dire en passant d'un processus à l'autre. L'expédition est la suivante :

enregistrer le contexte du thread actuel qui doit être modifié ;

lancement d'un nouveau thread pour exécution.

Le contexte du thread reflète, premièrement, l'état du matériel informatique au moment de l'interruption (la valeur du compteur de programme, le contenu des registres à usage général, le mode de fonctionnement du processeur, les drapeaux, les masques d'interruption et d'autres paramètres), et d'autre part, les paramètres de l'environnement d'exploitation (liens vers les fichiers ouverts, données sur les opérations d'E/S en attente, codes d'erreur des appels système exécutés par ce thread, etc.).

Dans le cadre d'un thread, on peut distinguer une partie commune à tous les threads d'un processus donné (liens vers des fichiers ouverts), et une partie qui ne s'applique qu'à un thread donné (contenu des registres, compteur de programme, mode processeur) . Par exemple, dans l'environnement NetWare, il existe trois types de contextes : le contexte global (contexte de processus), le contexte de groupe de threads et le contexte de thread individuel. La relation entre les données de ces contextes est similaire à la relation entre les variables globales et locales dans un programme. L'organisation hiérarchique des contextes accélère le changement de thread : lors du passage d'un thread d'un groupe à un thread d'un autre groupe au sein d'un même processus, le contexte global ne change pas, mais seul le contexte du groupe change. La commutation de contexte global se produit uniquement lorsque vous passez d'un thread dans un processus à un thread dans un autre processus.

3. Algorithmes de planification

Du point de vue de la résolution du premier problème d'ordonnancement (choix du moment pour changer le thread actif), les algorithmes d'ordonnancement sont divisés en deux grandes classes - les algorithmes préemptifs et non préemptifs :

sans déplacement- le thread actif peut être exécuté jusqu'à ce qu'il transfère lui-même le contrôle au système afin qu'il sélectionne un autre thread prêt dans la file d'attente ;

déplacer– le système d'exploitation décide de changer la tâche en cours et bascule le processeur sur un autre thread.

La principale différence entre ces algorithmes d'ordonnancement est le degré de centralisation du mécanisme d'ordonnancement des flux. Considérez les principales caractéristiques, avantages et inconvénients de chaque classe d'algorithmes.

Algorithmes non préemptifs. Le programme d'application, ayant reçu le contrôle du système d'exploitation, détermine lui-même le moment d'achèvement du cycle suivant de son exécution et ne transfère alors le contrôle au système d'exploitation qu'à l'aide d'un appel système. Par conséquent, le contrôle de l'application par l'utilisateur est perdu pendant une durée arbitraire. Les développeurs doivent en tenir compte et concevoir des applications de manière à ce qu'elles fonctionnent comme si elles étaient en "parties", en interrompant périodiquement et en transférant le contrôle au système, c'est-à-dire lors du développement, les fonctions de l'ordonnanceur sont également exécutées.

Avantages cette approche:

– interruption du flux à un moment inopportun car il est exclu ;

– le problème de l'utilisation simultanée des données est résolu, car lors de chaque cycle d'exécution, la tâche les utilise exclusivement et est sûre que personne d'autre ne peut les modifier ;

– vitesse de commutation plus rapide d'un flux à l'autre.

désavantages sont le développement difficile de programmes et les exigences accrues pour la qualification d'un programmeur, ainsi que la possibilité de capturer le processeur par un thread en cas de bouclage accidentel ou délibéré.

Algorithmes préemptifs- un ordonnancement de type cyclique ou circulaire, dans lequel le système d'exploitation décide lui-même d'interrompre ou non l'application active et fait basculer le processeur d'une tâche à l'autre selon l'un ou l'autre critère. Dans un système avec de tels algorithmes, le programmeur n'a pas à se soucier du fait que son application sera exécutée simultanément avec d'autres tâches. Les exemples incluent les systèmes d'exploitation UNIX, Windows NT/2000, OS/2. Les algorithmes de cette classe sont axés sur l'exécution d'applications hautes performances.

Les algorithmes préemptifs peuvent être basés sur le concept de quantification ou sur un mécanisme de priorité.

Algorithmes basés sur la quantification. Chaque thread reçoit un quantum continu limité de temps processeur (sa valeur ne doit pas être inférieure à 1 ms - en règle générale, plusieurs dizaines de ms). Le fil passe de l'état en cours d'exécution à l'état prêt si le quantum est épuisé. Les quanta peuvent être les mêmes pour tous les threads ou différents.

Lors de l'attribution de quanta à un flux, différents principes peuvent être utilisés : ces quanta peuvent être d'une valeur fixe ou évoluer à différentes périodes de la vie du flux. Par exemple, pour un thread particulier, le premier quantum peut être assez grand, et chaque quantum suivant qui lui est alloué peut avoir une durée plus courte (réduction à des limites spécifiées). Cela crée un avantage pour les threads plus courts et les tâches de longue durée passent en arrière-plan. Un autre principe repose sur le fait que les processus qui effectuent fréquemment des opérations d'E/S n'utilisent pas pleinement les intervalles de temps qui leur sont alloués. Pour compenser cette injustice, une file d'attente distincte peut être formée à partir de ces processus, qui a des privilèges par rapport aux autres threads. Lors du choix du prochain thread à exécuter, cette file d'attente est d'abord parcourue, et seulement si elle est vide, un thread est sélectionné dans la file d'attente générale prête à être exécutée.

Ces algorithmes n'utilisent aucune information préalable sur les tâches. La différenciation des services dans ce cas est basée sur "l'historique d'existence" du flux dans le système.

Du point de vue du second problème d'ordonnancement (le principe de choix du prochain thread à exécuter), les algorithmes peuvent également être conditionnellement divisés en classes : algorithmes non prioritaires et prioritaires. En service non prioritaire, la tâche suivante est sélectionnée dans un ordre prédéterminé sans tenir compte de leur importance relative et du temps de service. Lors de la mise en œuvre des disciplines prioritaires, certaines tâches ont le droit prioritaire d'entrer dans l'état d'exécution.

Examinons maintenant certaines des disciplines de planification les plus courantes.


Service premier arrivé premier servi. L'attribution du processeur s'effectue selon le principe FIFO (First In First Out), c'est-à-dire dans l'ordre de réception des demandes de service. Cette approche nous permet de mettre en place la stratégie « si possible, terminer les calculs dans l'ordre où ils apparaissent ». Les tâches qui ont été bloquées dans le processus d'exécution, après le passage à l'état prêt, sont mises en file d'attente avant les tâches qui n'ont pas encore été exécutées. Ainsi, deux files d'attente sont créées : l'une des tâches qui n'ont pas encore été exécutées et l'autre des tâches qui sont passées de l'état d'attente.

Cette discipline est implémentée de manière non préemptive, lorsque les tâches libèrent volontairement le processeur.

Dignité de cet algorithme est sa facilité de mise en œuvre. désavantage– avec une charge importante, les travaux courts sont obligés d'attendre longtemps dans le système. L'approche suivante élimine cette lacune.

Le processus le plus court est servi en premier. Selon cet algorithme, le thread avec le temps estimé minimum requis pour terminer son travail est assigné ensuite pour être exécuté. Ici, les flux qui ont encore un peu de temps avant de se terminer sont préférés. Cela réduit le nombre de tâches en attente dans le système. désavantage est la nécessité de connaître à l'avance les délais estimés, ce qui n'est pas toujours possible. Comme approximation grossière, dans certains cas, vous pouvez utiliser le temps passé par le thread lorsqu'il a reçu le contrôle pour la dernière fois.

L'algorithme appartient à la catégorie des algorithmes non prioritaires non préemptifs.

Les algorithmes nommés peuvent être utilisés pour les modes de fonctionnement par lots lorsque l'utilisateur ne s'attend pas à ce que le système réponde. Pour l'informatique interactive, il faut tout d'abord assurer un temps de réponse acceptable et une égalité de service pour des systèmes multiterminaux. Pour les systèmes mono-utilisateur, il est souhaitable que les programmes directement utilisés aient un meilleur temps de réponse que les tâches en arrière-plan. De plus, certaines applications, tout en s'exécutant sans la participation directe de l'utilisateur, doivent néanmoins être garanties de recevoir leur part de temps processeur (par exemple, le programme de réception de courrier électronique). Pour résoudre ces problèmes, des méthodes de service prioritaire et le concept de quantification sont utilisés.


discipline du carrousel, ou circulaireRR(Round Robin). Cette discipline appartient aux algorithmes préemptifs et est basée sur la quantification. Chaque tâche reçoit du temps processeur en morceaux - quanta. Après la fin du quantum de temps, la tâche est retirée du processeur et placée à la fin de la file d'attente des processus prêts à être exécutés, et la tâche suivante est acceptée pour traitement par le processeur. Pour le fonctionnement optimal du système, il est nécessaire de bien choisir la loi selon laquelle les tranches de temps sont allouées aux tâches.

La valeur quantique est choisie comme un compromis entre un temps de réponse acceptable du système aux requêtes des utilisateurs (afin que leurs requêtes les plus simples ne provoquent pas une longue attente) et la surcharge des changements de tâche fréquents. Lors des interruptions, le système d'exploitation doit enregistrer une quantité suffisante d'informations sur le processus en cours, mettre le descripteur de la tâche terminée dans la file d'attente et charger le contexte de la nouvelle tâche. Avec un petit quantum de temps et des commutations fréquentes, la part relative de ces frais généraux deviendra importante, ce qui dégradera les performances du système dans son ensemble. Avec un grand quantum de temps et une augmentation de la file d'attente des tâches prêtes, la réaction du système deviendra mauvaise.

Dans certains systèmes d'exploitation, il est possible de spécifier explicitement la valeur du quantum de temps ou la plage autorisée de ses valeurs. Par exemple, sous OS/2, le fichier CONFIG.SYS spécifie les valeurs minimale et maximale pour une tranche de temps à l'aide de l'instruction TIMESLICE : TIMESLICE=32,256 indique que la tranche de temps peut être modifiée entre 32 et 256 millisecondes.

Cette discipline de service est l'une des plus courantes. Dans certains cas, lorsque le système d'exploitation ne prend pas explicitement en charge la discipline de la planification circulaire, une telle maintenance peut être organisée artificiellement. Par exemple, certains RTOS utilisent un ordonnancement avec des priorités absolues, et lorsque les priorités sont égales, le principe de priorité est appliqué. Autrement dit, seule une tâche avec une priorité plus élevée peut supprimer une tâche de l'exécution. Si nécessaire, organiser le service de manière égale et équitable, c'est-à-dire afin que tous les travaux reçoivent les mêmes créneaux horaires, l'opérateur du système peut mettre en œuvre lui-même cette maintenance. Pour ce faire, il suffit d'attribuer les mêmes priorités à toutes les tâches utilisateur et de créer une tâche hautement prioritaire qui ne doit rien faire d'autre que d'être programmée pour être exécutée par une minuterie à des intervalles de temps spécifiés. Cette tâche supprimera uniquement l'application en cours de l'exécution, elle se déplacera à la fin de la file d'attente et la tâche elle-même quittera immédiatement le processeur et la donnera au processus suivant dans la file d'attente.

Dans sa mise en œuvre la plus simple, une discipline de service carrousel suppose que tous les travaux ont la même priorité. S'il est nécessaire d'introduire un mécanisme de service prioritaire, généralement plusieurs files d'attente sont organisées, en fonction des priorités, et la file d'attente de priorité inférieure n'est desservie que lorsque la file d'attente de priorité supérieure est vide. Cet algorithme est utilisé pour la planification sur les systèmes OS/2 et Windows NT.

Planification selon les priorités.

Un concept important derrière de nombreux algorithmes préemptifs est le service prioritaire. De tels algorithmes utilisent les informations trouvées dans le descripteur de thread - sa priorité. Différents systèmes définissent la priorité différemment. Dans certains systèmes, la valeur de priorité la plus élevée peut être considérée comme sa valeur numériquement la plus élevée, dans d'autres, au contraire, zéro est considéré comme la priorité la plus élevée.

En règle générale, la priorité d'un thread est directement liée à la priorité du processus dans lequel le thread s'exécute. Processus prioritaire est attribué par le système d'exploitation lors de sa création, en tenant compte du fait que le processus est un système ou un processus d'application, quel est le statut de l'utilisateur qui a lancé le processus et si l'utilisateur a explicitement indiqué que le processus devait se voir attribuer un certain priorité. La valeur de priorité est incluse dans le descripteur de processus et est utilisée lors de l'attribution d'une priorité à ses threads. Si le thread n'a pas été initié par une commande utilisateur, mais à la suite d'un appel système exécuté par un autre thread, alors le système d'exploitation doit prendre en compte les paramètres de l'appel système pour lui attribuer une priorité.

Lors de la planification de la maintenance du programme selon les algorithmes décrits précédemment, une situation peut survenir lorsque certaines tâches de contrôle ou de gestion ne peuvent pas être mises en œuvre pendant une longue période en raison d'une augmentation de la charge du système (en particulier dans le RTOS). Dans le même temps, les conséquences dues à l'achèvement prématuré de ces tâches peuvent être plus graves que celles dues à l'échec de la mise en œuvre de certains programmes plus prioritaires. Dans ce cas, il conviendra de changer temporairement la priorité des tâches "d'urgence" (celles dont le temps de traitement est compté), et de restaurer la valeur précédente après exécution. L'introduction de mécanismes de modification dynamique des priorités permet de mettre en œuvre une réponse système plus rapide aux demandes courtes des utilisateurs (ce qui est important pour le travail interactif), mais garantit en même temps l'exécution de toutes les demandes.

La priorité peut donc être statique(fixe) ou dynamique(système changeant en fonction de la situation dans celui-ci). Soi-disant priorité de thread de base dépend directement de la priorité de base du processus qui l'a engendré. Dans certains cas, le système peut augmenter la priorité d'un thread (et à des degrés divers), par exemple, si le quantum de temps processeur qui lui est alloué n'a pas été entièrement utilisé, ou abaisser la priorité dans le cas contraire. Par exemple, le système d'exploitation augmente davantage la priorité pour les threads en attente d'une entrée au clavier et moins pour les threads effectuant des opérations sur le disque. Dans certains systèmes qui utilisent le mécanisme des priorités dynamiques, des formules assez complexes sont utilisées pour modifier la priorité, qui impliquent les valeurs des priorités de base, le degré de chargement du système informatique, la valeur initiale de la priorité spécifiée par l'utilisateur , etc.

Il existe deux types de planification prioritaire : maintenance avec des priorités relatives et services avec priorité absolue. Dans les deux cas, le choix d'un thread à exécuter s'effectue de la même manière - le thread avec la priorité la plus élevée est sélectionné et le moment du changement de thread actif est déterminé différemment. Dans un système avec des priorités relatives, un thread actif s'exécute jusqu'à ce qu'il quitte le processeur lui-même (passe à un état d'attente, ou une erreur se produit, ou le thread se termine). Dans un système avec des priorités absolues, l'interruption d'un thread actif, en plus des raisons ci-dessus, se produit également si un thread avec une priorité plus élevée que l'actif apparaît dans la file d'attente des threads prêts. Ensuite, le thread en cours d'exécution est interrompu et transféré à l'état prêt.

Dans un système avec une planification basée sur des priorités relatives, les coûts de commutation sont minimisés, mais une tâche peut prendre beaucoup de temps sur le processeur. Pour les systèmes en temps partagé et en temps réel, ce mode de service ne convient pas, mais dans les systèmes de traitement par lots (par exemple, OS / 360), il est largement utilisé. La planification à priorité absolue convient aux systèmes de gestion des installations où une réponse rapide aux événements est importante.

Type de planification mixte utilisé dans de nombreux systèmes d'exploitation : les algorithmes d'ordonnancement basés sur les priorités sont combinés au concept de quantification.

Le cœur du système d'exploitation UNIX est le sous-système de contrôle de processus. Pratiquement toutes les activités du noyau sont liées aux processus, qu'il s'agisse de traiter un appel système, de générer un signal, d'allouer de la mémoire, de gérer les exceptions causées par l'exécution d'un processus ou de fournir des services d'E/S à la demande d'un processus d'application.
Toutes les fonctionnalités du système d'exploitation sont finalement déterminées par l'exécution de certains processus, tout comme les niveaux d'exécution du système (niveaux d'exécution) ne sont rien de plus qu'une forme pratique de définition d'un groupe de processus en cours d'exécution. La possibilité d'accès terminal ou réseau au système, les différents services traditionnels d'UNIX - le système d'impression, les archives distantes FTP, le courrier électronique et le système de conférence de presse - tout cela est le résultat de certains processus. Les processus sous UNIX sont inextricablement liés à deux des ressources système les plus importantes, le processeur et la RAM. En règle générale, il n'y a jamais "beaucoup" de ces ressources, et il y a une concurrence active dans le système d'exploitation pour le droit de posséder le processeur et la mémoire. Et comme UNIX est un système multitâche à usage général, la tâche de répartir équitablement cette ressource entre des tâches de différentes classes et avec des exigences différentes n'est pas triviale.
Parce qu'un programme en cours d'exécution crée un ou plusieurs
processus (ou tâches). Le sous-système de contrôle de processus contrôle :
  • Création et suppression de processus
  • Répartition des ressources système (mémoire, ressources de calcul) entre les processus
  • Synchronisation des processus
  • Communication interprocessus
Évidemment, dans le cas général, le nombre de processus actifs dépasse le nombre de processeurs informatiques,
mais un seul processus peut être exécuté sur chaque processeur à un moment donné. Le système d'exploitation contrôle l'accès des processus aux ressources informatiques,
créer un sentiment de multi-tâches en même temps. Une tâche spéciale du noyau appelée planificateur de processus résout les conflits entre les processus en compétition pour les ressources système (processeur, mémoire, périphériques d'E/S). Le planificateur lance un processus pour s'assurer que le processus ne monopolise pas les ressources système partagées. Le processus libère le processeur en attendant une longue opération d'E/S, ou aprèsquantité de temps. Dans ce cas, le planificateur sélectionne le processus suivant avec la priorité la plus élevée et exécutepour l'exécution.

Module de gestion de la mémoire fournit l'allocation de RAM pour les tâches de l'application. Dans le cas où il n'y a pas assez de mémoire pour tous les processus, le noyau déplace des parties du processus
ou plusieurs processus vers la mémoire secondaire (généralement une zone spéciale du disque dur), libérant des ressources pour le processus en cours d'exécution.

Tous les systèmes modernes implémentent ce qu'on appelle la mémoire virtuelle : un processus s'exécute dans son propre espace d'adressage logique, qui peut être beaucoup plus grand que la mémoire physique disponible. La gestion de la mémoire virtuelle des processus fait également partie des tâches du module de gestion de la mémoire.
Module de communication interprocessus est chargé de notifier les processus des événements à l'aide de signaux et offre la possibilité de transférer des données entre différents processus.

Principes de base du contrôle de processus

Un processus UNIX est une image de programme exécutable qui inclut un mappage de mémoire - un fichier exécutable obtenu à la suite d'une compilation, c'est-à-dire o il existe des traductions de modules de programme, langages de haut niveau, en modules de programme équivalents de la languebas niveau comme ceci:données de pile, de code et de bibliothèque, ainsi qu'un certain nombre de structures de données du noyau nécessaires au contrôle des processus, ce qui est un point très important pour mieux comprendre les principes d'allocation de mémoire, en tant que l'une des ressources les plus importantes dans la "concurrence" des processus , c'est-à-dire que les données sont structurées !, sous réserve :
  • Pile (c courant ) est une zone mémoire dans laquelle le programme stocke des informations sur les fonctions appelées, leurs arguments et chaque variable locale dans les fonctions. La taille de la zone peut changer au cours de l'exécution du programme. Lorsqu'une fonction est appelée, la pile s'agrandit et lorsqu'elle se termine, elle se rétrécit.
  • Heap (à l'enseignement ) est une zone de mémoire où un programme peut faire ce qu'il veut. La taille de la zone peut changer. Le programmeur a la possibilité d'utiliser une partie de la mémoire du tas à l'aide de la fonction malloc(), puis cette zone mémoire est augmentée. Les ressources sont renvoyées à l'aide de free() , après quoi le tas est réduit.
  • Code (à un segment ) est une zone de mémoire qui stocke les instructions machine d'un programme compilé. Ils sont générés par le compilateur, mais peuvent aussi être écrits à la main. Notez que cette zone mémoire peut également être divisée en trois parties (texte, données et BSS). Cette zone mémoire a une taille fixe déterminée par le compilateur.UNIX. Programmation professionnelle art.259

Cela prédéterminera (y compris) davantage l'émergence (l'existence) de segments et de pages. Lors de son exécution, un processus utilise diverses ressources système : mémoire, processeur, services de sous-système de fichiers et sous-systèmes d'E/S. La dure vérité de tout complexe informatique moderne est qu'un processeur ne peut servir qu'un seul processus par unité de temps, ce qui à son tour a prédéterminél'émergence (l'existence) d'un "scheduler", au moyen duquelLe système d'exploitation UNIX donne l'illusion d'exécuter plusieurs processus en même temps en allouant efficacement les ressources système aux processus actifs tout en empêchant l'un d'entre eux de monopoliser l'utilisation de ces ressources.

Le nouveau système d'exploitation UNIX ne fournissait que deux processus, un pour chaque terminal connecté au PDP-7. Un an plus tard, sur le même PDP-7, le nombre de processus a nettement augmenté, un appel système est apparu fourchette. La première édition d'UNIX a introduit le défi ex, mais le système d'exploitation n'autorisait toujours qu'un seul processus à être placé en mémoire à la fois. Après la mise en œuvre du sous-système de gestion de la mémoire matérielle sur le PDP-11, le système d'exploitation a été modifié pour permettre le chargement simultané de plusieurs processus en mémoire, réduisant ainsi le temps nécessaire pour stocker une image de processus dans la mémoire secondaire (sur disque) et lisez-le pendant que le processus était encore en cours d'exécution. Jusqu'en 1972, cependant, UNIX n'était pas vraiment un système multitâche, car les opérations d'E/S restaient synchrones et les autres processus ne pouvaient pas s'exécuter tant que leur « collègue » n'avait pas terminé l'opération d'E/S. Le véritable multitâche n'est apparu qu'après la réécriture du code UNIX en C en 1973. Depuis lors, les bases de la gestion des processus n'ont pas beaucoup changé.


L'exécution du processus peut se produire en deux modes - en mode noyau ( mode noyau) ou en mode tâche ( mode utilisateur). En mode tâche, un processus exécute des instructions de programme d'application autorisées par un niveau de sécurité de processeur non privilégié. Dans ce cas, les structures de données système ne sont pas disponibles pour le processus. Lorsqu'un processus a besoin de recevoir un service du noyau, il effectue un appel système qui exécute les instructions du noyau qui sont au niveau privilégié.

Même si les instructions du noyau sont exécutées, elles proviennent du nom du processus qui a effectué l'appel système. L'exécution du processus passe alors en mode noyau. Ainsi, le noyau du système protège son propre espace d'adressage d'un accès par le processus applicatif, qui peut violer l'intégrité des structures de données du noyau et conduire à la destruction du système d'exploitation.

De plus, certaines instructions du processeur, telles que les changements de registres liés à la gestion de la mémoire, ne peuvent être exécutées qu'en mode noyau.
Par conséquent, l'image de processus se compose de deux parties : les données du mode noyau et les données du mode tâche. Une image de processus en mode tâche se compose d'un segment de code, de données, d'une pile, de bibliothèques et d'autres structures de données auxquelles elle peut accéder directement. Une image de processus en mode noyau se compose de structures de données non disponibles pour un processus en mode tâche, qui sont utilisées par le noyau pour gérer le processus.. Cela inclut les données dictées par le matériel, telles que les états des registres, les tables de mappage de la mémoire, etc., ainsi que les structures de données dont le noyau a besoin pour gérer le processus. De manière générale, en mode noyau, un processus peut accéder à n'importe quelle zone de la mémoire.

Traiter les structures de données

Chaque processus est représenté dans le système par deux structures de données principales. proc et utilisateur,

décrites, respectivement, dans les dossiers sys/proc.h et sys/utilisateur.h. Le contenu et le format de ces structures varient selon les versions d'UNIX.

....................................................................................................

https://m.habr.com/ru/company/*nix<-----------
….................................................................................................
A tout moment, ces structures proc car tous les processus doivent être présents en mémoire, bien que d'autres structures de données, y compris l'image de processus, puissent être déplacées vers la mémoire secondaire, la zone d'échange. Cela permet au noyau d'avoir à portée de main les informations minimales nécessaires pour localiser le reste des données liées au processus, même si elles ne sont pas en mémoire. Structure proc est une entrée dans la table des processus système, qui, comme nous venons de le remarquer, est toujours dans la RAM. L'entrée dans cette table pour le processus en cours d'exécution est adressée par la variable système curproc. Chaque fois qu'un changement de contexte est effectué, lorsque les ressources du processeur sont transférées vers un autre
processus, la valeur de la variable change en conséquence curproc, qui pointe maintenant vers la structure proc processus actif. La deuxième structure mentionnée utilisateur, aussi appelé zone u ou bloc en u, contient des données supplémentaires sur le processus requises par le noyau uniquement pendant l'exécution du processus (c'est-à-dire lorsque le processeur exécute les instructions du processus en mode noyau ou tâche). Contrairement à la structure proc, adressé par le pointeur curproc, Les données utilisateur sont placés
(plus précisément, affichés) à un certain endroit de la mémoire virtuelle du noyau et sont adressés par une variable tu. Les deux principales structures de données de processus et la manière dont elles sont traitées par le noyau UNIX sont présentées ci-dessous.
À zone u stocke les données utilisées par de nombreux sous-systèmes du noyau et pas seulement pour le contrôle des processus. En particulier, il contient des informations sur les descripteurs de fichiers ouverts, la disposition des signaux, les statistiques d'exécution des processus et les valeurs de registre enregistrées lorsque le processus est suspendu. Évidemment, un processus ne devrait pas pouvoir modifier ces données arbitrairement, donc u-area est protégé contre l'accès en mode tâche. Comme on peut le voir sur la Fig., zone u contient également une pile de taille fixe, la pile système ou la pile noyau. Lorsqu'un processus s'exécute en mode noyau, le système d'exploitation utilise cette pile au lieu de la pile de processus normale.

États de processus

Le cycle de vie d'un processus peut être divisé en plusieurs états. La transition d'un processus d'un état à un autre se produit en fonction de l'occurrence de certains événements dans le système.
  • 1. Le processus s'exécute en mode tâche. Dans le même temps, les instructions d'application de ce processus sont exécutées par le processeur.
  • 2. Le processus s'exécute en mode noyau. En même temps, le processeur exécute des instructions systèmenoyau du système d'exploitation au nom du processus.
  • 3 . Le processus n'est pas en cours d'exécution, mais il est prêt à s'exécuter dès que le planificateurle sélectionnera (état exécutable). Le processus est mis en file d'attente pour exécution et a tousressources dont il a besoin, à l'exception de l'informatique.
  • 4. Le processus est dans un état de veille (endormi), en attente d'un accès inaccessiblele moment actuel de la ressource, tel que l'achèvement d'une opération d'E/S.
  • 5. Le processus revient du mode noyau au mode tâche, mais le noyau l'interrompt et exécutechangement de contexte pour exécuter un processus de priorité plus élevée.
  • 6. Le processus vient d'être créé par fork et est en transition.état : il existe, mais n'est pas prêt à fonctionner et n'est pas en état de veille.
  • 7. Le processus a exécuté l'appel système exit et est entré dans l'étatzombies (zombie, défunt). En tant que tel, le processus n'existe pas, mais les enregistrements restent,contenant le code retour et les statistiques temporaires de son exécution, disponibles pour le processus parent.Cet état est l'état final du cycle de vie du processus.
Il convient de noter que tous les processus ne passent pas par tous les états énumérés ci-dessus. Le processus commence son chemin de vie à partir de l'état 6 lorsque le processus parent effectue un appel système fourchette(). Une fois la création du processus complètement terminée, le processus met fin à "l'enfant" de l'appel et passe à l'état 3 prêt à lancer, en attente de votre
file d'attente d'exécution. Lorsque le planificateur sélectionne un processus à exécuter, il entre dans l'état 1 et s'exécute en mode tâche. L'exécution en mode tâche se termine à la suite d'un appel système ou d'une interruption, et le processus passe en mode noyau, dans lequel l'appel système ou le code d'interruption est exécuté. Le processus peut alors revenir en mode tâche à nouveau. Cependant, lors d'un appel système en mode noyau, un processus peut avoir besoin d'une ressource qui n'est pas disponible actuellement. Pour attendre l'accès à une telle ressource, le processus appelle la fonction noyau dormir() et s'endort 4 . Dans le même temps, le processus libère volontairement des ressources informatiques, qui sont fournies au processus de priorité la plus élevée suivante. Lorsqu'une ressource devient disponible, le noyau "réveille le processus" à l'aide de la fonction réveillez-vous() le met en file d'attente pour exécution et le processus entre dans l'état "prêt à fonctionner" 3 .
Lorsqu'un processus reçoit des ressources informatiques, un changement de contexte se produit, à la suite duquel l'image, ou le contexte, du processus actuel est enregistré et le contrôle est transféré au nouveau. Un changement de contexte peut se produire, par exemple, si un processus s'est endormi ou si un processus avec une priorité supérieure à celle en cours est prêt à s'exécuter. Dans ce dernier cas, le noyau ne peut pas terminer immédiatement le processus en cours et effectuer un changement de contexte. Le fait est qu'un changement de contexte lorsqu'il est exécuté en mode noyau peut entraîner une violation de l'intégrité du système lui-même.
Par conséquent, le changement de contexte est différé jusqu'à ce que le processus passe du mode noyau au mode tâche, lorsque toutes les opérations système sont terminées et que les structures de données du noyau sont dans un état normal.
Ainsi, après que l'ordonnanceur a sélectionné un processus à exécuter, ce dernier démarre son
exécution en mode noyau, où le changement de contexte se termine. État supplémentaire
processus dépend de son historique : si le processus vient d'être créé ou a été interrompu, en revenant en mode tâche, il bascule immédiatement dans ce mode. Si un processus commence à s'exécuter après l'état de veille, il continue de s'exécuter en mode noyau, mettant fin à l'appel système. Notez qu'un tel processus peut être interrompu après la fin de l'appel système au point de transition du mode noyau au mode tâche, s'il existe un processus de priorité plus élevée dans la file d'attente. UNIX 4xBSD définit des états de processus supplémentaires, principalement liés au système de contrôle des travaux et aux interactions processus-terminal. Le processus peut être mis à l'état "arrêté" à l'aide de signaux d'arrêt SIGSTOP, SIGTIN ou SIGTTOU. Contrairement aux autres signaux, qui ne sont traités que pour un processus en cours d'exécution, l'envoi de ces signaux entraîne un changement d'état immédiat. Dans ce cas, si le processus est en cours d'exécution ou en attente de démarrage, son état passe à "arrêté". Si le processus était en état de veille, son état passera à "arrêté en état de veille". La sortie de ces états s'effectue par le signal de poursuite CONT SIG, avec le processus passant de l'état "arrêté" à l'état "prêt à fonctionner", et pour un processus arrêté dans l'état de veille, la prochaine destination est de continuer la "veille".
Les fonctionnalités décrites sont entièrement implémentées dans SVR4.

Il existe une exception pour les processus qui sont en état de veille pendant
un événement de faible priorité, c'est-à-dire un événement qui a peu de chances de se produire (par exemple, une saisie au clavier qui peut ne pas se produire).

Enfin, le processus effectue un appel système sortir() et termine son exécution. Le processus peut également être terminé en raison de la réception d'un signal. Dans les deux cas, le noyau libère les ressources détenues par le processus, à l'exception du code retour et de ses statistiques d'exécution, etmet le processus dans l'état "zombie". Le processus est dans cet état jusqu'à ce que le processus parent exécute l'un des appels système, après quoi toutes les informations sur le processus sont détruites, et le parent reçoit le code de retour du processus terminé.

Principes de gestion de la mémoire

Marshal Kirk McKusick FreeBSD - Architecture et implémentation<<-----------PDF ст.166

Gestion de la mémoire partie-1

12:51 - Résolution d'adresse 34:21 - Superposition, structure dynamique

59:26 - Cartographie continue linéaire - Linéaire par morceaux (article 25)


Gestion de la mémoire partie-2

Qu'y avait-il au début ? OOP ou mémoire virtuelle.

51:44--> "Mémoire virtuelle" ;<-(стр. 18)->56:03--> "Segments" ;


Tampon d'association de traduction, Tampon de recherche de traduction(TLB) est un cache CPU spécialisé utilisé pour accélérer la traduction d'une adresse de mémoire virtuelle en une adresse de mémoire physique.
https://en.wikipedia.org
https://www.ibm.com/support/knowledgecenter/.performance/cache_tlbs.htm

L'une des principales fonctions du système d'exploitation est la gestion efficace de la mémoire.
RAM, ou mémoire principale, ou mémoire vive (Random Access Memory, RAM). Le temps d'accès à la RAM n'est que de quelques cycles de processeur, donc travailler avec des données en mémoire offre des performances maximales.
Cette ressource est généralement limitée. Dans une plus large mesure, cela est vrai pour un système d'exploitation polyvalent multitâche, qui est UNIX.
Par conséquent, les données qui ne peuvent pas être placées dans la mémoire principale sont situées sur des périphériques de stockage secondaires, ou dans la mémoire secondaire, dont le rôle est généralement joué par
Disques durs. Le temps d'accès à la mémoire secondaire est supérieur de plusieurs ordres de grandeur au temps d'accès à la mémoire principale et nécessite l'assistance active du système d'exploitation.
Le sous-système de gestion de la mémoire UNIX est responsable de l'allocation juste et efficace des
ressource RAM partagée entre les processus et pour l'échange de données entre la RAM et la mémoire secondaire. Certaines opérations sont effectuées par le matériel
unité de gestion de la mémoire (MMU) du processeur exécutant le système d'exploitation, qui atteint les performances requises.
La gestion primitive de la mémoire réduit considérablement les fonctionnalités du système d'exploitation. De tels systèmes, en règle générale, permettent de charger une seule tâche dans un emplacement prédéterminé de la RAM et de lui transférer le contrôle. Dans ce cas, la tâche reçoit
disposition de toutes les ressources informatiques (en les partageant, bien sûr, avec le système d'exploitation),
et les adresses utilisées par la tâche sont des adresses physiques de la mémoire principale.
Étant donné que cette méthode de lancement et d'exécution d'un programme unique est de loin la plus rapide, elle est souvent utilisée dans les systèmes à microprocesseur spécialisés, mais est pratiquement inapplicable dans les systèmes d'exploitation à usage général, tels que UNIX.
Nous pouvons formuler un certain nombre de fonctionnalités que le sous-système de gestion de la mémoire d'un système d'exploitation multitâche moderne devrait fournir :

  • Exécuter des tâches qui dépassent la taille de l'opérationnel Mémoire.
  • Exécution de tâches partiellement chargées en mémoire pour minimiserleur heure de lancement.
  • Placer plusieurs tâches en mémoire en même temps pour améliorer l'efficacité du processeur.
  • Placer une tâche à un endroit arbitraire dans la RAM.
  • Placer une tâche dans plusieurs parties différentes de la RAM.
  • Partage des mêmes zones de mémoire par plusieurs tâches.Par exemple, plusieurs processus exécutant le même programme peuvent partager un segment de code.
  • la possibilité de créer des codes indépendants de la machine, c'est-à-dire qu'il ne devrait y avoir a priori aucun lien entre le programme et la mémoire physique.
Toutes ces fonctionnalités sont implémentées dans les versions modernes d'UNIX en utilisant mémoire virtuelle, les performances du système d'exploitation multitâche dans son ensemble dépendent largement de l'efficacité de la mise en œuvre et du fonctionnement de ce sous-système. Cela vous permet de donner à l'application l'illusion qu'une grande quantité de mémoire est disponible, alors qu'en réalité l'ordinateur peut n'avoir qu'une petite quantité de RAM. Cela nécessite la définition d'une abstraction "d'espace d'adressage" distincte de l'emplacement physique de la mémoire. Le programme crée des liens vers des codes et des données dans son espace d'adressage, ces adresses doivent être converties en adresses de cellules RAM. Le transfert d'informations vers la mémoire principale pour une utilisation par le programme et l'exécution d'une traduction d'adresse sur chaque accès à la mémoire obligent à la fois le logiciel et le matériel de l'ordinateur à travailler ensemble.
PS:Linux

De plus, le processus fonctionne avec des adresses virtuelles, pas avec des adresses physiques.

La conversion est effectuée par des calculs à l'aide de tables de descripteurs et de catalogues de tables.

Linux prend en charge 3 niveaux de tables : le répertoire de tables de premier niveau ( DPI- Répertoire des tables de pages),

répertoire de table de second niveau ( PMD- Medium Page Table Directory), et enfin la table des descripteurs (ETP- Entrée de table de pages). En réalité, tous les niveaux peuvent ne pas être pris en charge par un processeur particulier,mais le headroom lui permet de supporter plus d'architectures possibles (Intel a 2 niveaux de tables, et Alpha - jusqu'à 3).

La transformation d'une adresse virtuelle en adresse physique se déroule respectivement en 3 étapes. Le pointeur est pris DPI, présent dans la structure décrivant chaque processus, est converti en un pointeur d'enregistrement PMD, et ce dernier est converti en un pointeur dans la table des descripteurs ETP. Et enfin à la vraie adresse,pointant vers le début de la page est ajouté un décalage par rapport à son début. Un bon exemple d'une telle procédure peut être trouvé dans la fonction noyau< clear_partial>.


Mémoire virtuelle et physique

La RAM est l'un des composants importants d'un système informatique. Les premiers systèmes UNIX avaient 64 Ko de RAM à leur disposition, et cette quantité n'était clairement pas suffisante, les ordinateurs modernes ont des gigaoctets de RAM, et ce n'est toujours pas suffisant.
La RAM peut être représentée comme une séquence d'octets, chacun ayant sa propre adresse unique, appelée adresse physique. Ce sont ces adresses que le processeur utilise finalement lors de l'échange de données avec la RAM. Cependant, l'espace d'adressage d'un processus est très différent de l'espace d'adressage de la RAM physique. Imaginez que l'espace d'adressage d'un processus corresponde directement à la mémoire principale, en d'autres termes, que les adresses utilisées par le processus soient des adresses physiques. Avec cette approche, un certain nombre d'obstacles insurmontables nous attendraient sur la voie de la création d'un système multitâche :
  • Tout d'abord, il est difficile d'imaginer un mécanisme qui protège l'espace d'adressage d'un seul processus,de l'espace d'adressage d'un autre, ou plus important encore, de l'espace d'adressage du système d'exploitation lui-même.Étant donné que chaque processus fonctionne avec des adresses physiques, il n'y a aucune garantie que le processus n'accédera pasemplacements de mémoire appartenant à d'autres processus ou au noyau du système.Les conséquences d'un tel traitement risquent d'être très déplorables.
  • Deuxièmement, déjà au stade de la compilation, il faudrait prévoir la distributionespace d'adressage physique existant. Au démarrage, chaque processus doitoccupent une zone continue et non superposée d'adresses physiques.
  • Troisièmement, une telle répartition de la mémoire entre les processus est peu probablepeut être qualifié d'optimal. Volume de physique opérationnella mémoire limitera considérablement le nombre de processus,s'exécutant simultanément sur le système. Donc huit processus,chacun occupe 1 Mo de mémoire, manquera de 8 MoRAM et le système d'exploitation sous charge moyennea plus de 80 processus!
Tous ces problèmes peuvent être surmontés à l'aide de la mémoire virtuelle.
Dans le même temps, les adresses utilisées par les applications et le noyau lui-même ne doivent pas nécessairement correspondre à des adresses physiques. Les adresses virtuelles sont traduites ou mappées sur des adresses physiques au niveau matériel avec la participation active du noyau du système d'exploitation.La signification de la mémoire virtuelle est que chaque processus s'exécute dans son propre espace d'adressage virtuel..

L'espace d'adressage virtuel est un paradis pour un processus.

  • Tout d'abord, le processus a un sens d'exclusivité - après tout, tout l'espace d'adressagen'appartient qu'à lui.
  • Deuxièmement, il n'est plus limité par la quantité de mémoire physique - la mémoire virtuelle peut considérablementdépasser le physique. En conséquence, les processus sont isolés les uns des autres et n'ont pasopportunités (même si vous le souhaitez)"hôte" dans l'espace d'adressage du voisin. La mémoire physique est allouée autant que possibleefficace - cela ne dépend pas de l'allocation de mémoire virtuelle d'un processus individuel.
De toute évidence, un mécanisme de mappage géré est nécessaire pour implémenter la mémoire virtuelle.
adresse virtuelle à physique. Dans les systèmes informatiques modernes, le processus de cartographie est effectué dans le matériel (à l'aide MMU)(Bit MMU (bit utilisé)), fournissant une vitesse de transmission élevée.
Le système d'exploitation gère ce processus.

En règle générale, les processeurs modernes prennent en charge l'union de l'espace d'adressage (segment - organisation des pages de la mémoire):

dans régions de taille variable - segments et

dans zones de taille fixe - pages,

la notion de "page" peut être interprétée comme une manière d'organiser la mémoire lorsque la mémoire physique est divisée en blocs de taille fixe (512-2Ko, un multiple de 2), ainsi que la notion de "segment", "page" est l'une des abstractions fondamentales pour comprendre l'architecture et le fonctionnement des systèmes d'exploitation. Dans ce cas, pour chaque segment ou page, son propre mappage des adresses virtuelles aux adresses physiques peut être défini.
L'espace d'adressage virtuel d'un processus est généralement structuré séquentiellement en segments - code, données, pile et bibliothèques. L'emplacement des zones correspondantes de la mémoire physique peut être fragmenté personnage. La taille de la mémoire virtuelle peut dépasser de manière significative la taille de la mémoire physique en raison de l'utilisation de la mémoire secondaire ou d'une zone d'échange - généralement de l'espace disque, où des parties temporairement inutilisées de l'espace d'adressage du processus peuvent être stockées. Par exemple, si un processus accède à une adresse virtuelle pour laquelle il existe une page de mémoire physique correspondante, l'opération de lecture ou d'écriture réussira. S'il n'y a pas de page dans la RAM, le processeur génère une interruption matérielle appelée défaut de page ( erreur de page), en réponse à quoi le noyau détermine la position du contenu de la page enregistrée dans la zone d'échange, lit la page en mémoire, définit les paramètres de mappage des adresses virtuelles aux adresses physiques et demande au processeur de répéter l'opération. Toutes ces actions sont invisibles pour une application qui fonctionne avec de la mémoire virtuelle.
Le mécanisme de mappage des adresses virtuelles aux adresses physiques (traduction d'adresse) est essentiel

manière dépend de l'implémentation matérielle spécifique. Cette section décrit le mécanisme de mappage des adresses virtuelles aux adresses physiques dans le système d'exploitation SCO UNIX en utilisant la famille de processeurs Intel comme exemple. Cependant, comme pour les autres sous-systèmes UNIX, les principes de base diffèrent peu, et cette présentation permettra d'introduire les mécanismes de gestion de la mémoire et de comprendre, si nécessaire, une implémentation spécifique.

segments

La famille de processeurs Intel permet de diviser la mémoire en plusieurs blocs logiques appelés segments. Dans ce cas, l'espace d'adressage d'un processus peut être représenté par plusieurs segments logiques, dont chacun est constitué d'une séquence continue d'adresses comprises dans une plage donnée. Traduction d'adresse basée sur la segmentation,
fournit un mappage sans ambiguïté des adresses de segment dans une séquence continue
adresses physiques. L'adresse virtuelle dans ce cas se compose de deux parties : le sélecteur de segment et
décalage par rapport au début du segment. Sélecteur(plus précisément, le champ de sélection INDICE) pointe vers
le descripteur dit de segment contenant des paramètres tels que son emplacement en mémoire,
taille et autorisations. Le processeur prend en charge l'adressage indirect des segments via des descripteurs de segment, qui sont situés dans des tables spéciales - des zones de mémoire pointées par
registres du sous-traitant destinés à cet effet. Le noyau du système d'exploitation est responsable du remplissage de ces tables et de la définition des valeurs de registre. En d'autres termes, le noyau définit le mappage et le processeur effectue le mappage dans le matériel. Grâce à cet adressage indirect, les segments logiques sont protégés les uns des autres, ce qui garantit l'intégrité des espaces d'adressage du processus et du noyau.
Les descripteurs de segment sont situés dans deux tables système - table de descripteurs locaux
(Tableau des descripteurs locaux - LDT) et le tableau des descripteurs globaux - TDG).
Comme son nom l'indique, LDT fournit une traduction d'adresse virtuelle des segments de processus,
tandis que le GDT maintient l'espace d'adressage du noyau (par exemple, lors du traitement du système
appel ou interruption). Chaque processus crée son propre LDT, tandis que le GDT
partagé par tous les processus. Les informations sur la table vers laquelle pointe le sélecteur se trouvent dans le sélecteur lui-même.

1 5 3 2 1 0

INDICE TI RPL
Sélecteur de segments
  • Champ INDICE est le numéro (index) du descripteur dans la table des descripteurs, qui doitêtre utilisé lors du calcul de l'adresse linéaire.
  • Bit TI spécifie quelle table de descripteurs doit être utiliséeØ - conforme aux GDT1 - correspond à LDT
  • Champ RPL est utilisé pour contrôler les droits d'accès du programme au segment. Est demandéniveau de privilège et est l'un des mécanismes permettant d'assurer la protection du segment.Par exemple, si un processus, en mode tâche, tente d'accéder à un segment,appartenant au noyau, le processeur générera une exception, en réponse à laquelle le noyau enverra le signal SIGSEGV au processus.
Chaque entrée LDT ou GDT est un descripteur de segment. Plusieurs types de descripteurs sont définis, utilisés pour les segments de code, de données et de pile, ainsi qu'un certain nombre de descripteurs,
qui permettent le multitâche et le transfert de contrôle d'une tâche non privilégiée, comme un processus en mode tâche, à une tâche privilégiée, comme le noyau.
Les descripteurs utilisés dans ce dernier cas sont appelés passerelles.

Les descripteurs de segment (code, data, stack) comportent plusieurs champs :

  • Adresse de base Ce champ stocke l'adresse 32 bits du début du segment. Le processeur y ajoutedécalage et obtient une adresse linéaire de 32 bits.
  • Limite Ce champ spécifie la taille du segment. Si le résultatl'adresse linéaire est hors segment, le processeur génère une exception.Les limites de segment permettent au processeur de détecter les erreurs courantes telles que les débordements de pile,pointeurs invalides, adresses d'appel invalides ettransitions. Lorsque le système d'exploitation considère quel'accès hors segment n'est pas une erreur(par exemple en cas de débordement de pile), il peut étendre le segment en allouantmémoire supplémentaire et demander que la commande soit exécutée à nouveau.
  • Privileges Ce champ, appelé Descriptor Privilege Level (DPL), définit le niveauprivilèges de segment et est utilisé en conjonction avec le champ de sélecteur RPL pour autoriser ou refuser l'accèsà la tranche. Pour accéder à un segment, une tâche doit être au moins du même niveauprivilèges, commesegment, c'est-à-dire RPL DPL.
  • Signe de présence. Ce bit fournit l'un des mécanismes d'implémentation de la mémoire virtuelle.Si le bit n'est pas défini, lors de la tentative d'accèsà un segment, le processeur génère une exception manquante.segment, permettant au noyau de charger le segment depuis la mémoire secondaire et de répéter à nouveau l'instruction,sans affecter l'exécution du processus. Cependant, dans la plupart des versions modernesLa mémoire virtuelle UNIX est basée sur un mécanisme de pagination,dans lequel le segment est toujours présent en mémoire, et l'échange entre opérationnel etle stockage secondaire se produit au niveau de la page.
  • Type Ce champ spécifie le type de segment. Le processeur vérifie le typesegment pour correspondre à la commande exécutable. Ceci, en particulier, ne permet pas d'interpréterinformations de segment de données sous forme d'instructions de processeur.
  • Autorisations Ce champ définit les autorisations qui restreignent l'ensemble desopérations pouvant être effectuées sur le segment. Par exemple,un segment de code est généralement marqué comme exécutable et lisible.Les segments de données peuvent avoir un accès en lecture seule,ou pour lire et écrire.
La combinaison du sélecteur et du décalage forme une adresse logique. Unité de contrôle de la mémoire du processeur
utilise un sélecteur pour déterminer son descripteur correspondant. En ajoutant l'adresse de base du segment stocké dans le descripteur avec le décalage, le processeur crée une adresse linéaire. Si la pagination n'est pas utilisée, l'adresse linéaire résultante est l'adresse physique utilisée pour l'accès direct à la mémoire principale. Cependant, l'implémentation de la mémoire virtuelle basée uniquement sur les segments n'est pas assez flexible et n'est pas utilisée dans les versions modernes. La gestion de la mémoire dans la plupart des systèmes est basée sur un mécanisme de page. Les segments sont utilisés par le noyau pour héberger le code, les données et la pile d'un processus, chacun avec une adresse de base de zéro et une limite de 3 Go, c'est-à-dire toute la mémoire virtuelle adressable moins le 1 Go occupé par le noyau du système.
La répartition de l'espace d'adressage virtuel entre le noyau et les processus est abordée dans " ".

Mécanisme de page

Lors de la mise en œuvre d'une mémoire virtuelle basée uniquement sur la segmentation, le segment entier peut être soit présent dans la mémoire principale, soit absent (plus précisément, être dans la mémoire secondaire ou dans le fichier exécutable du processus).
Étant donné que la taille du segment peut être assez importante, plusieurs processus volumineux s'exécutant en même temps entraîneront de graves conflits pour les ressources mémoire, ce qui à son tour
entraînera un échange de données intensif entre la RAM et la mémoire secondaire. De plus, l'échange de régions de taille variable, qui sont des segments, est assez compliqué et, bien que la fragmentation de la mémoire soit faible, elle conduira à une faible efficacité de son utilisation,
laissant une grande quantité d'espace inutilisé.

Le mécanisme de pagination offre beaucoup plus de flexibilité. Dans ce cas, tout l'espace d'adressage virtuel (4 Go pour les processeurs Intel) est divisé en blocs de même taille, appelés pages. La plupart des processeurs Intel fonctionnent avec des pages de 4 Ko. Comme dans le cas de la segmentation, la page peut soit être présente en RAM,
ou être dans l'espace d'échange ou l'exécutable du processus. Le principal avantage d'un tel schéma est que le système de gestion de la mémoire fonctionne avec des régions d'une taille suffisamment petite.
taille pour assurer une distribution efficace des ressources mémoire entre les processus.
Le mécanisme de pagination permet à une partie d'un segment d'être en RAM et à une autre non. Cela permet au noyau d'allouer en mémoire uniquement les pages actuellement utilisées par le processus, libérant ainsi considérablement de la RAM. Un autre avantage est que les pages d'un segment peuvent être situées dans la mémoire physique dans un emplacement et un ordre arbitraires, ce qui permet une utilisation efficace de l'espace libre.
Cette approche ressemble au schéma de stockage de fichiers sur un disque - chaque fichier se compose de
un nombre différent de blocs de stockage de données pouvant être situés dans n'importe quelle zone libre du lecteur de disque. Cela conduit à une fragmentation importante, mais améliore considérablement l'efficacité de l'espace disque.

Lors de l'utilisation du mécanisme de radiomessagerie, l'adresse linéaire obtenue en ajoutant l'adresse de base du segment et le décalage est également une adresse logique, qui est ensuite traitée par l'unité de radiomessagerie du processeur. Dans ce cas, l'adresse linéaire est traitée par le processeur comme constituée de trois parties.


Entrée de répertoire de pages, PDE- Le premier champ d'adresse, bits 22 à 31, pointe vers l'entrée du répertoire de la table des pages EDP. Le répertoire de table de pages fait une page et contient jusqu'à 1024 pointeurs de table de page. Ainsi, le premier champ adresse une table de pages spécifique.
Entrée de table de pages, PTE- Le deuxième champ, occupé de 12 à 21 bits, indique l'entrée de la table des pages RTE. Les tables de pages ont également une longueur de 4 Ko et les entrées de table adressent un total de 1024 pages. En d'autres termes, le deuxième champ adresse une page spécifique.
Enfin, le décalage de page est déterminé par le troisième champ, qui occupe les 12 bits inférieurs de l'adresse linéaire. Ainsi, avec un seul répertoire de table, un processus peut adresser

1024 x 1024 x 4096 = 4 Go de mémoire physique.

La figure ci-dessus montre comment le bloc de pagination du processeur traduit une adresse linéaire en une adresse physique. Le processeur utilise le champ d'adresse PDE (10 bits de poids fort) comme index dans le répertoire de la table. Trouvél'élément contient l'adresse de la table des pages. Le deuxième champ d'adresse linéaire PTE permet au processeur de sélectionnerl'élément de tableau souhaité adressant la page physique. Ajout de l'adresse du début de la page avec un décalage,stocké dans le troisième champ, le processeur reçoit une adresse physique de 32 bits.

La plupart des processeurs modernes, et en particulier la famille de processeurs Intel, placent les données sur les dernières pages utilisées par eux dans un cache ultra-rapide. Ce n'est que lorsque le processeur ne trouve pas la page requise dans ce cache qu'il accède au répertoire et aux tables de pages. En règle générale, 99 à 98% des liens d'adresse entrent dans le cache, sans nécessiter l'adresse d'accès à la RAM, où se trouvent le répertoire et les tables, pour la traduction.
Chaque élément de la table des pages contient plusieurs champs décrivant divers

caractéristiques des pages. des champs ETP:


P
Un signe de présence en RAM. L'accès à une page qui n'est pas en mémoire (P=0) provoque un défaut de page, une condition particulière dont le processeur informe le noyau, qui le gère de manière appropriée.
L/E Autorisations de lire la page uniquement (R/W=0) ou de lire et d'écrire (R/W=1)

NOUS
Privilèges d'accès. Si U/S=0, seules les tâches privilégiées(core) ont accès aux adresses de page. Sinon, l'accès àpage ont toutes les tâches.
Adresse Adresse physique du début de la page (adresse de base)

Espace d'adressage de processus

L'espace d'adressage du noyau est généralement le même que l'espace d'adressage du processus en cours d'exécution. Dans ce cas, le noyau est dit situé dans le même contexte que le processus. Chaque fois qu'un processus reçoit des ressources de calcul, le système restaure
le contexte de tâche du processus, qui comprend les valeurs des registres à usage général, des registres de segment et des pointeurs de table de page qui représentent la mémoire virtuelle du processus en mode tâche. Dans ce cas, le contexte système reste inchangé pour tous les processus. La vue de l'espace d'adressage du processus est illustrée dans la figure ci-dessous.

L'un des principaux sous-systèmes de tout système d'exploitation multiprogramme moderne qui affecte directement le fonctionnement d'un ordinateur est le sous-système de contrôle des processus et des threads. Les principales fonctions de ce sous-système :

    créer des processus et des threads ;

    doter les processus et les flux des ressources nécessaires ;

    isolement du processus;

    planifier l'exécution des processus et des threads (en général, on devrait aussi parler de planification des tâches) ;

    planification des threads ;

    organisation de la communication interprocessus ;

    synchronisation des processus et des threads ;

    arrêt et destruction des processus et des threads.

1. Cinq événements principaux conduisent à la création d'un processus :

    répondre à une requête de processus en cours d'exécution pour créer un processus ;

    inviter l'utilisateur à créer un processus, par exemple lors d'une connexion interactive ;

    lancement d'un travail par lots ;

    la création par le système d'exploitation d'un processus nécessaire au fonctionnement de tout service.

Habituellement, lorsque le système d'exploitation démarre, plusieurs processus sont créés. Certains d'entre eux sont des processus hautement prioritaires qui permettent une interaction avec les utilisateurs et exécutent un travail donné. Les autres processus sont des processus d'arrière-plan, ils ne sont pas associés à des utilisateurs spécifiques, mais exécutent des fonctions spéciales - par exemple, liées au courrier électronique, aux pages Web, à la sortie vers sceller, transfert de fichier sur réseau, lancement périodique de programmes (par exemple, défragmentation de disque) etc. Les processus d'arrière-plan sont appelés démons.

Un nouveau processus peut être créé sur demande du processus en cours. La création de nouveaux processus est utile lorsque la tâche à exécuter peut être plus facilement formée comme un ensemble de processus coopérants liés, mais néanmoins indépendants. Dans les systèmes interactifs utilisateur peut lancer un programme en tapant une commande sur le clavier ou en double-cliquant sur l'icône du programme. Dans les deux cas, un nouveau processus est créé et lancement programmes dedans. À systèmes de traitement par lots sur les ordinateurs centraux, les utilisateurs soumettent un travail (éventuellement en utilisant un accès à distance), et le système d'exploitation crée un nouveau processus et démarre le travail suivant dans la file d'attente lorsque les ressources requises se libèrent.

2. D'un point de vue technique, dans tous ces cas, un nouveau processus se forme de la même manière : le processus courant exécute le système demande pour créer un nouveau processus. Le sous-système de gestion des processus et des threads est chargé de fournir aux processus les ressources nécessaires. Le système d'exploitation conserve des structures d'informations spéciales en mémoire, dans lesquelles il enregistre les ressources allouées à chaque processus. Il peut affecter des ressources à un processus pour un usage exclusif ou pour les partager avec d'autres processus. Certaines des ressources sont allouées au processus lors de sa création et d'autres sont allouées dynamiquement. sur demandes pendant délai de mise en œuvre. Les ressources peuvent être allouées à un processus pour toute sa durée de vie ou seulement pour une période spécifique. Lors de l'exécution de ces fonctions, le sous-système de contrôle de processus interagit avec d'autres sous-systèmes du système d'exploitation responsables de la gestion des ressources, comme le sous-système de gestion de la mémoire, Sous-système d'E/S, système de fichiers.

3. Pour empêcher les processus d'interférer avec affectation des ressources, et ne pourraient pas non plus endommager les codes et les données de l'autre, la tâche la plus importante du système d'exploitation est d'isoler un processus d'un autre. Pour ça système opérateur fournit à chaque processus un espace d'adressage virtuel distinct afin qu'aucun processus ne puisse accéder directement aux commandes et aux données d'un autre processus.

4. Dans un système d'exploitation où des processus et des threads existent, un processus est considéré comme une demande de consommation de tous les types de ressources, à l'exception d'un - le temps processeur. Ce plus important Ressource est distribué par le système d'exploitation parmi d'autres unités de travail - les threads, qui tirent leur nom du fait qu'il s'agit de séquences (flux d'exécution) de commandes. Le passage de l'exécution d'un thread à un autre s'effectue à la suite dePlanification etexpéditeur . Travailler sur Déterminer quand interrompre l'exécution du thread actuel et du thread qui doit être autorisé à s'exécuter s'appelle la planification. La planification des threads est basée sur les informations stockées dans les descripteurs de processus et de threads. La planification tient compte priorité de thread, leur temps d'attente dans la file d'attente, cumulé délai de mise en œuvre, le taux d'accès aux E/S et d'autres facteurs.

5. Le dispatching consiste en la mise en œuvre de la solution trouvée à la suite de la planification, c'est-à-dire pour faire passer le processeur d'un thread à un autre. L'expédition se déroule en trois étapes :

    enregistrer le contexte du fil en cours ;

    lancement d'un nouveau thread pour exécution.

6. Lorsque plusieurs tâches indépendantes s'exécutent sur le système en même temps, des problèmes supplémentaires surviennent. Bien que les threads soient créés et exécutés de manière synchrone, ils peuvent avoir besoin d'interagir, par exemple, lors de l'échange de données. Les processus et les threads peuvent utiliser un large éventail de fonctionnalités pour communiquer entre eux : canaux (en UNIX), boîtes aux lettres ( les fenêtres), appel de procédure distante, sockets (en les fenêtres connecter des processus sur différentes machines). La correspondance du taux de thread est également très importante pour éviter les conditions de concurrence (lorsque plusieurs threads tentent de modifier le même dossier), blocages et autres collisions qui se produisent lors du partage de ressources.

7. Synchronisation threads est l'une des fonctions les plus importantes du sous-système de gestion des processus et des threads. Les systèmes d'exploitation modernes fournissent de nombreux mécanismes de synchronisation, notamment des sémaphores, des mutex, des régions critiques et des événements. Tous ceux-ci mécanismes travailler avec des threads, pas des processus. C'est pourquoi quand couler est bloqué sur le sémaphore, d'autres threads de ce processus peuvent continuer à s'exécuter.

8. Chaque fois qu'un processus se termine, - et cela se produit en raison de l'un des événements suivants : l'habituel sortir, sortir sur erreur, sortir sur erreur fatale, destruction par un autre processus - le système d'exploitation prend des mesures pour "nettoyer les traces" de son séjour dans le système. Le sous-système de contrôle de processus ferme tous les fichiers avec lesquels le processus a travaillé, libère des zones de RAM allouées aux codes, aux données et aux structures d'informations système du processus. Réalisé correction toutes sortes de files d'attente du système d'exploitation et liste ressources qui contenaient des références au processus en cours de terminaison.

isolement du processus;
  • planifier l'exécution des processus et des threads (en général, on devrait aussi parler de planification des tâches) ;
  • planification des threads ;
  • organisation de la communication interprocessus ;
  • synchronisation des processus et des threads ;
  • arrêt et destruction des processus et des threads.
  • Cinq événements principaux conduisent à la création d'un processus :

  • répondre à une requête de processus en cours d'exécution pour créer un processus ;
  • inviter l'utilisateur à créer un processus, par exemple lors d'une connexion interactive ;
  • lancement d'un travail par lots ;
  • la création par le système d'exploitation d'un processus nécessaire au fonctionnement de tout service.
  • Habituellement, lorsque le système d'exploitation démarre, plusieurs processus sont créés. Certains d'entre eux sont des processus hautement prioritaires qui permettent une interaction avec les utilisateurs et exécutent un travail donné. Les autres processus sont des processus d'arrière-plan, ils ne sont pas associés à des utilisateurs spécifiques, mais remplissent des fonctions spéciales - par exemple, liées à la messagerie électronique, aux pages Web, à l'impression, au transfert de fichiers sur le réseau, au lancement périodique de programmes (par exemple, défragmentation de disque) etc. Les processus d'arrière-plan sont appelés démons.

    Un nouveau processus peut être créé à la demande du processus en cours. La création de nouveaux processus est utile lorsque la tâche à exécuter peut être plus facilement formée comme un ensemble de processus coopérants liés, mais néanmoins indépendants. Sur les systèmes interactifs, l'utilisateur peut démarrer le programme en tapant une commande sur le clavier ou en double-cliquant sur l'icône du programme. Dans les deux cas, un nouveau processus est créé et le programme y est lancé. À systèmes de traitement par lots sur les ordinateurs centraux, les utilisateurs soumettent un travail (éventuellement en utilisant un accès à distance), et le système d'exploitation crée un nouveau processus et démarre le travail suivant dans la file d'attente lorsque les ressources requises se libèrent.

    D'un point de vue technique, dans tous ces cas, un nouveau processus est formé de la même manière : le processus courant exécute une requête système pour créer un nouveau processus. Le sous-système de gestion des processus et des threads est chargé de fournir aux processus les ressources nécessaires. Le système d'exploitation conserve des structures d'informations spéciales en mémoire, dans lesquelles il enregistre les ressources allouées à chaque processus. Il peut affecter des ressources à un processus pour un usage exclusif ou pour les partager avec d'autres processus. Certaines des ressources sont allouées au processus lors de sa création, et d'autres sont allouées dynamiquement en fonction des demandes lors de délai de mise en œuvre. Les ressources peuvent être allouées à un processus pour toute sa durée de vie ou seulement pour une période spécifique. Lors de l'exécution de ces fonctions, le sous-système de contrôle de processus interagit avec d'autres sous-systèmes du système d'exploitation responsables de la gestion des ressources, comme le sous-système de gestion de la mémoire, Sous-système d'E/S, système de fichiers.

    Pour empêcher les processus d'interférer avec affectation des ressources, et ne pouvaient pas non plus endommager les codes et les données les uns des autres, la tâche la plus importante du système d'exploitation est d'isoler un processus d'un autre. Pour ça système opérateur fournit à chaque processus un espace d'adressage virtuel distinct afin qu'aucun processus ne puisse accéder directement aux commandes et aux données d'un autre processus.

    Dans un système d'exploitation où des processus et des threads existent, un processus est considéré comme une demande de consommation de tous les types de ressources, à l'exception d'un - le temps processeur. Cette ressource critique est distribuée par le système d'exploitation parmi d'autres unités de travail - les threads, qui tirent leur nom du fait qu'il s'agit de séquences (flux d'exécution) de commandes. Le passage de l'exécution d'un thread à un autre s'effectue à la suite de Planification et expéditeur. Le travail consistant à déterminer quand interrompre le thread en cours et le thread qui doit être autorisé à s'exécuter est appelé planification. La planification des threads est basée sur les informations stockées dans les descripteurs de processus et de threads. La planification tient compte priorité de thread, leur temps d'attente dans la file d'attente, cumulé délai de mise en œuvre, le taux d'accès aux E/S et d'autres facteurs.

    Le dispatching consiste en la mise en œuvre de la solution trouvée à la suite de la planification, c'est-à-dire pour faire passer le processeur d'un thread à un autre. L'expédition se déroule en trois étapes :

    • enregistrer le contexte du fil en cours ;
    • charger le contexte de fil sélectionné à la suite de l'ordonnancement ;
    • lancement d'un nouveau thread pour exécution.

    Lorsque plusieurs tâches indépendantes s'exécutent sur le système en même temps, des problèmes supplémentaires surviennent. Bien que les threads soient créés et exécutés de manière synchrone, ils peuvent avoir besoin d'interagir, par exemple, lors de l'échange de données. Pour communiquer entre eux, les processus et les threads peuvent utiliser un large éventail de fonctionnalités : canaux (sous UNIX), boîtes aux lettres (Windows), appels de procédure à distance, sockets (dans les processus de connexion Windows sur différentes machines). La correspondance du taux de thread est également très importante pour éviter les conditions de concurrence (lorsque plusieurs threads tentent de modifier le même fichier), les blocages et autres collisions qui se produisent lors du partage des ressources.

    Synchronisation threads est l'une des fonctions les plus importantes du sous-système de gestion des processus et des threads. Les systèmes d'exploitation modernes fournissent de nombreux mécanismes de synchronisation, notamment des sémaphores, des mutex, des régions critiques et des événements. Tous ces mécanismes fonctionnent avec des threads, pas avec des processus. Ainsi, lorsqu'un thread se bloque sur un sémaphore, les autres threads de ce processus peuvent continuer à s'exécuter.

    Chaque fois qu'un processus se termine - et cela est dû à l'un des événements suivants : sortie normale, sortie sur erreur, sortie sur erreur fatale, être tué par un autre processus - le système d'exploitation prend des mesures pour "nettoyer les traces" de sa présence dans le système. Le sous-système de contrôle de processus ferme tous les fichiers avec lesquels le processus a travaillé, libère des zones de RAM allouées aux codes, aux données et aux structures d'informations système du processus. Toutes les files d'attente possibles du système d'exploitation et la liste des ressources contenant des liens vers le processus en cours d'arrêt sont corrigées.

    Comme indiqué, afin de soutenir multiprogrammation, le système d'exploitation doit organiser lui-même les unités de travail internes entre lesquelles le processeur et les autres ressources informatiques seront divisés. La question se pose : quelle est la différence fondamentale entre ces unités de travail, quel effet de multiprogrammation peut-on obtenir de leur utilisation, et dans quels cas faut-il créer ces unités de travail du système d'exploitation ?

    Évidemment, tout travail d'un système informatique consiste en l'exécution d'un programme. Par conséquent, un certain code de programme est associé à la fois au processus et au thread, qui est conçu comme un module exécutable. Dans le cas le plus simple, un processus consiste en un seul thread, et certains systèmes d'exploitation modernes ont conservé cette position. Multiprogrammation dans de tels systèmes d'exploitation est effectuée au niveau du processus. Si une interaction est nécessaire, les processus se tournent vers le système d'exploitation, qui, agissant en tant qu'intermédiaire, leur fournit des outils de communication interprocessus - canaux, actions de messagerie, sections de mémoire partagée, etc.

    Cependant, dans les systèmes qui n'ont pas le concept de thread, des problèmes surviennent lors de l'organisation du calcul parallèle au sein d'un processus. Et un tel besoin peut survenir. Le fait est qu'un seul processus ne peut jamais être exécuté plus rapidement qu'en mode programme unique. Cependant, une application s'exécutant dans le même processus peut avoir parallélisme interne, ce qui, en principe, pourrait accélérer sa solution. Si, par exemple, le programme prévoit d'accéder à un périphérique externe, alors pendant la durée de cette opération, il est possible de ne pas bloquer l'exécution de l'ensemble du processus, mais de poursuivre les calculs en utilisant une autre branche du programme.

    L'exécution parallèle de plusieurs tâches au sein d'une même application interactive augmente l'efficacité du travail de l'utilisateur. Ainsi, lorsque vous travaillez avec un éditeur de texte, il est souhaitable de pouvoir combiner la saisie d'un nouveau texte avec des opérations aussi longues que le reformatage d'une partie importante du texte, l'enregistrant sur un disque local ou distant.

    Il n'est pas difficile d'imaginer une future version du compilateur capable de compiler automatiquement les fichiers de code source dans les pauses qui se produisent lors de la saisie d'un programme. Ensuite, des avertissements et des messages d'erreur apparaîtraient en temps réel, et l'utilisateur verrait immédiatement ce qu'il a fait d'une erreur. Les feuilles de calcul modernes recalculent les données en arrière-plan dès que l'utilisateur modifie quelque chose. Les traitements de texte divisent le texte en pages, vérifient les fautes d'orthographe et de grammaire, tapent en arrière-plan, enregistrent le texte toutes les quelques minutes, etc. Dans tous ces cas, les threads sont utilisés comme moyen de paralléliser les calculs.

    Ces tâches pourraient être assignées à un programmeur qui aurait à écrire un programme répartiteur qui implémente le parallélisme au sein d'un processus unique. Cependant, cela est très difficile et le programme lui-même se révélerait très déroutant et difficile à déboguer.

    Une autre solution consiste à créer plusieurs processus pour une application pour chacune des applications parallèles.