Un processus est un programme en cours d'exécution et fait partie intégrante de tout système d'exploitation moderne . Le système d'exploitation doit allouer des ressources aux processus , permettre aux processus de partager et d'échanger des informations, protéger les ressources de chaque processus des autres processus et permettre la synchronisation entre les processus. Pour répondre à ces exigences, le système d'exploitation doit conserver une structure de données pour chaque processus, qui décrit l'état et la propriété des ressources de ce processus, et qui permet au système d'exploitation d'exercer un contrôle sur chaque processus.
Multiprogrammation
Dans tout système d'exploitation moderne, plusieurs instances d'un programme peuvent être chargées en mémoire en même temps. Par exemple, plusieurs utilisateurs peuvent exécuter le même programme, chacun ayant des copies distinctes du programme chargées en mémoire. Avec certains programmes, il est possible d'avoir une copie chargée en mémoire, tandis que plusieurs utilisateurs ont un accès partagé à celle-ci afin qu'ils puissent chacun exécuter le même code de programme. Un tel programme est appelé réentrant . À un instant donné, le processeur ne peut exécuter qu'une seule instruction d'un programme, mais plusieurs processus peuvent être maintenus sur une période de temps en affectant chaque processus au processeur à intervalles réguliers tandis que les autres deviennent temporairement inactifs. L'exécution de plusieurs processus sur une période de temps, plutôt que simultanément, est appelée exécution simultanée.
Un système d' exploitation multiprogrammation ou multitâche est un système capable d'exécuter plusieurs processus simultanément. La multiprogrammation nécessite que le processeur soit alloué à chaque processus pendant une période donnée et qu'il soit libéré ou libéré au moment opportun. Si le processeur est libéré pendant l'exécution d'un processus, cela doit être fait de manière à ce que le processus puisse redémarrer ultérieurement aussi efficacement que possible.
Il existe deux manières pour un système d'exploitation de reprendre le contrôle du processeur pendant l'exécution d'un programme afin que le système d'exploitation puisse effectuer une désallocation ou une allocation :
- Le processus émet un appel système (parfois appelé interruption logicielle ) ; par exemple, une demande d'E/S se produit pour accéder à un fichier sur un disque dur.
- Une interruption matérielle se produit ; par exemple, une touche a été enfoncée sur le clavier ou un minuteur expire (utilisé dans le multitâche préemptif ).
L'arrêt d'un processus et le démarrage (ou le redémarrage) d'un autre processus sont appelés changement de contexte ou changement de contexte. Dans de nombreux systèmes d'exploitation modernes, les processus peuvent être constitués de plusieurs sous-processus. Cela introduit le concept de thread . Un thread peut être considéré comme un sous-processus , c'est-à-dire une séquence d'exécution distincte et indépendante au sein du code d'un processus. Les threads deviennent de plus en plus importants dans la conception de systèmes distribués et client-serveur et dans les logiciels exécutés sur des systèmes multiprocesseurs .
Comment la multiprogrammation augmente l'efficacité
Un trait commun observé parmi les processus associés à la plupart des programmes informatiques est qu'ils alternent entre les cycles CPU et les cycles E/S . Pendant la partie du temps nécessaire aux cycles CPU, le processus est en cours d'exécution et occupe le CPU. Pendant le temps requis pour les cycles E/S, le processus n'utilise pas le processeur. Au lieu de cela, il attend d'effectuer une entrée/sortie ou effectue effectivement une entrée/sortie. Un exemple de cela est la lecture ou l'écriture dans un fichier sur le disque. Avant l'avènement de la multiprogrammation , les ordinateurs fonctionnaient comme des systèmes mono-utilisateur. Les utilisateurs de ces systèmes se rendent rapidement compte que pendant une grande partie du temps où un ordinateur était attribué à un seul utilisateur (par exemple, lorsqu'un utilisateur saisissait des informations ou déboguait des programmes), le processeur était inactif. Les informaticiens ont observé que les performances globales de la machine pouvaient être améliorées en laissant un processus différent utiliser le processeur chaque fois qu'un processus attendait une entrée/sortie. Dans un système de programmation unique , si N utilisateurs devaient exécuter des programmes avec des temps d'exécution individuels de t 1 , t 2 , ..., t N , alors le temps total, t uni , pour traiter les N processus (consécutivement) de tous les N utilisateurs serait :
- t uni = t 1 + t 2 + ... + t N .
Cependant, étant donné que chaque processus consomme à la fois des cycles CPU et des cycles d'E/S, le temps pendant lequel chaque processus utilise réellement le CPU représente une très petite fraction du temps d'exécution total du processus. Ainsi, pour le processus i :
- t i (processeur) ≪ t i (exécution)
où
t i (processeur) est le temps que le processus i passe à utiliser le CPU, et t i (exécution) est le temps total d'exécution du processus ; c'est-à-dire le temps nécessaire aux cycles CPU plus les cycles d'E/S à effectuer (exécuter) jusqu'à l'achèvement du processus.
En fait, généralement, la somme de tout le temps processeur, utilisé par N processus, dépasse rarement une petite fraction du temps d’exécution de l’un des processus ;
Par conséquent, dans les systèmes à programmation unique, le processeur reste inactif pendant une grande partie du temps. Pour surmonter cette inefficacité, la multiprogrammation est désormais implémentée dans les systèmes d'exploitation modernes tels que Linux , UNIX et Microsoft Windows . Cela permet au processeur de passer d'un processus, X, à un autre, Y, chaque fois que X est impliqué dans la phase d'E/S de son exécution. Étant donné que le temps de traitement est bien inférieur au temps d'exécution d'une seule tâche, le temps total nécessaire pour servir tous les N utilisateurs avec un système de multiprogrammation peut être réduit à environ :
- t multi = max( t 1 , t 2 , ..., t N )
Création de processus
Les systèmes d'exploitation ont besoin de moyens pour créer des processus. Dans un système très simple conçu pour exécuter une seule application (par exemple, le contrôleur d'un four à micro-ondes), il peut être possible d'avoir tous les processus qui seront nécessaires présents au démarrage du système. Dans les systèmes à usage général, cependant, il faut un moyen de créer et de terminer des processus selon les besoins pendant le fonctionnement.
Quatre événements principaux provoquent la création d'un processus :
- Initialisation du système.
- Exécution d'un appel système de création de processus par un processus en cours d'exécution.
- Une demande d'utilisateur pour créer un nouveau processus.
- Lancement d'un travail par lots.
Lors du démarrage d'un système d'exploitation, plusieurs processus essentiels sont généralement lancés pour préparer le système à fonctionner. Certains d'entre eux sont des processus de premier plan, qui interagissent avec un utilisateur (humain) et effectuent des tâches pour lui. D'autres sont des processus d'arrière-plan , qui ne sont pas associés à des utilisateurs particuliers, mais ont plutôt une fonction spécifique. Par exemple, un processus d'arrière-plan peut être conçu pour accepter les e-mails entrants, en dormant la majeure partie de la journée, mais en reprenant soudainement vie lorsqu'un e-mail entrant arrive. Un autre processus d'arrière-plan peut être conçu pour accepter les demandes entrantes de pages Web hébergées sur la machine, en se réveillant uniquement lorsqu'une demande arrive pour la traiter.
La création de processus sous UNIX et Linux s'effectue via des appels système fork() ou clone(). La création de processus comporte plusieurs étapes. La première étape consiste à vérifier si le processus parent dispose des autorisations suffisantes pour créer un processus. Une fois la validation réussie, le processus parent est copié presque entièrement, avec des modifications uniquement apportées à l'ID de processus unique, au processus parent et à l'espace utilisateur. Chaque nouveau processus obtient son propre espace utilisateur.
La création de processus dans Windows s'effectue via l'appel système CreateProcessA(). Un nouveau processus s'exécute dans le contexte de sécurité du processus appelant, mais s'exécute par ailleurs indépendamment du processus appelant. Il existe des méthodes permettant de modifier le contexte de sécurité dans lequel un nouveau processus s'exécute. Les nouveaux processus se voient attribuer des identifiants permettant d'y accéder. Des fonctions sont fournies pour synchroniser les threads appelants avec les processus nouvellement créés.
Fin du processus
Il existe de nombreuses raisons pouvant conduire à l’arrêt d’un processus :
- Les problèmes de travail par lots interrompent l'instruction
- L'utilisateur se déconnecte
- Le processus exécute une demande de service pour terminer
- Conditions d'erreur et de défaut
- Achèvement normal
- Délai dépassé
- Mémoire indisponible
- Violation des limites ; par exemple : tentative d'accès au 11e élément (inexistant) d'un tableau de 10 éléments
- Erreur de protection ; par exemple : tentative d'écriture dans un fichier en lecture seule
- Erreur arithmétique ; par exemple : tentative de division par zéro
- Dépassement de temps ; par exemple : le processus a attendu plus longtemps qu'un maximum spécifié pour un événement
- Échec d'E/S
- Instruction non valide ; par exemple : lorsqu'un processus tente d'exécuter des données (texte)
- Enseignement privilégié
- Utilisation abusive des données
- Intervention du système d'exploitation ; par exemple : pour résoudre un blocage
- Le parent se termine donc les processus enfants se terminent (terminaison en cascade)
- Demande des parents
Modèle de gestion de processus à deux états
La responsabilité principale du système d'exploitation est de contrôler l'exécution des processus . Cela comprend la détermination du modèle d'entrelacement pour l'exécution et l'allocation des ressources aux processus. Une partie de la conception d'un système d'exploitation consiste à décrire le comportement que nous souhaitons que chaque processus présente. Le modèle le plus simple repose sur le fait qu'un processus est soit exécuté par un processeur, soit non. Ainsi, un processus peut être considéré comme étant dans l'un des deux états, EN COURS D'EXÉCUTION ou NON EN COURS D'EXÉCUTION . Lorsque le système d'exploitation crée un nouveau processus, ce processus est initialement étiqueté comme NON EN COURS D'EXÉCUTION et est placé dans une file d'attente du système dans l' état NON EN COURS D'EXÉCUTION . Le processus (ou une partie de celui-ci) existe alors dans la mémoire principale et attend dans la file d'attente une opportunité d'être exécuté. Après un certain temps, le processus actuellement EN COURS D'EXÉCUTION sera interrompu et déplacé de l' état EN COURS D'EXÉCUTION à l' état NON EN COURS D'EXÉCUTION , rendant le processeur disponible pour un autre processus. La partie dispatch du système d'exploitation sélectionne alors, dans la file d'attente des processus NON EXÉCUTÉS , l'un des processus en attente à transférer au processeur. Le processus choisi est alors rebaptisé d'un état NON EXÉCUTÉ à un état EXÉCUTÉ , et son exécution est soit démarrée s'il s'agit d'un nouveau processus, soit reprise s'il s'agit d'un processus qui a été interrompu précédemment.
À partir de ce modèle, nous pouvons identifier certains éléments de conception du système d’exploitation :
- La nécessité de représenter et de suivre chaque processus
- L'état d'un processus
- La mise en file d'attente des processus NON EXÉCUTÉS
Modèle de gestion de processus à trois états
Bien que le modèle de gestion de processus à deux états soit une conception parfaitement valable pour un système d'exploitation, l'absence d'un état BLOQUÉ signifie que le processeur reste inactif lorsque le processus actif passe des cycles CPU aux cycles d'E/S . Cette conception n'utilise pas efficacement le processeur. Le modèle de gestion de processus à trois états est conçu pour surmonter ce problème, en introduisant un nouvel état appelé état BLOQUÉ . Cet état décrit tout processus qui attend qu'un événement d'E/S se produise. Dans ce cas, un événement d'E/S peut signifier l'utilisation d'un périphérique ou d'un signal provenant d'un autre processus. Les trois états de ce modèle sont les suivants :
- EN COURS D'EXÉCUTION : Le processus en cours d'exécution.
- PRÊT : Un processus en file d’attente et prêt à être exécuté lorsque l’opportunité lui en est donnée.
- BLOQUÉ : un processus qui ne peut pas s'exécuter tant qu'un événement ne se produit pas, comme la fin d'une opération d'E/S.
À tout instant, un processus se trouve dans un seul et unique des trois états. Pour un ordinateur monoprocesseur, un seul processus peut être dans l' état EN COURS D'EXÉCUTION à un instant donné. Il peut y avoir de nombreux processus dans les états PRÊT et BLOQUÉ , et chacun de ces états aura une file d'attente associée pour les processus.
Les processus entrant dans le système doivent d'abord passer à l' état READY , et les processus ne peuvent passer à l' état RUNNING que via l'état READY . Les processus quittent normalement le système à partir de l' état RUNNING . Pour chacun des trois états, le processus occupe de l'espace dans la mémoire principale. Si la raison de la plupart des transitions d'un état à un autre peut être évidente, certaines peuvent ne pas l'être autant.
- EN COURS D'EXÉCUTION → PRÊT : La raison la plus courante de cette transition est que le processus en cours d'exécution a atteint le temps maximal autorisé pour une exécution ininterrompue ; c'est-à-dire qu'un dépassement de délai se produit. D'autres raisons peuvent être l'imposition de niveaux de priorité tels que déterminés par la politique de planification utilisée pour le planificateur de bas niveau et l'arrivée d'un processus de priorité supérieure dans l'état PRÊT.
- EN COURS D'EXÉCUTION → BLOQUÉ : Un processus est placé dans l' état BLOQUÉ s'il demande quelque chose qu'il doit attendre. Une demande adressée au système d'exploitation se présente généralement sous la forme d'un appel système (c'est-à-dire un appel du processus en cours d'exécution à une fonction qui fait partie du code du système d'exploitation). Par exemple, un processus peut devenir BLOQUÉ s'il demande un fichier à partir du disque ou s'il enregistre une section de code ou des données de la mémoire dans un fichier sur le disque.
Description et contrôle du processus
Chaque processus du système est représenté par une structure de données appelée bloc de contrôle de processus (PCB) ou descripteur de processus sous Linux .
Identification du processus : Chaque processus est identifié de manière unique par l'identification de l'utilisateur et un pointeur le reliant à son descripteur.
État du processus : Ceci indique l'état actuel du processus ; PRÊT , EN COURS D'EXÉCUTION , BLOQUÉ , PRÊT SUSPENDRE , BLOQUÉ SUSPENDRE .
État du processus : contient toutes les informations nécessaires pour indiquer l’état actuel du travail.
Comptabilité : Cette rubrique contient des informations utilisées principalement à des fins de facturation et de mesure des performances. Elle indique le type de ressources utilisées par le processus et pendant combien de temps.
Modes du processeur
Les processeurs contemporains intègrent un bit de mode pour définir la capacité d'exécution d'un programme dans le processeur. Ce bit peut être défini sur le mode noyau ou le mode utilisateur . Le mode noyau est également communément appelé mode superviseur , mode moniteur ou anneau 0 .
En mode noyau, le processeur peut exécuter toutes les instructions de son répertoire matériel, tandis qu'en mode utilisateur, il ne peut exécuter qu'un sous-ensemble d'instructions. Les instructions qui ne peuvent être exécutées qu'en mode noyau sont appelées instructions noyau, privilégiées ou protégées pour les distinguer des instructions en mode utilisateur. Par exemple, les instructions d'E/S sont privilégiées. Ainsi, si un programme d'application s'exécute en mode utilisateur, il ne peut pas effectuer ses propres E/S . Au lieu de cela, il doit demander au système d'exploitation d'effectuer des E/S en son nom.
Le concept du système Kernel
Les parties critiques du système d'exploitation s'exécutent en mode noyau , tandis que les autres logiciels (tels que les utilitaires système et les programmes d'application) s'exécutent en mode utilisateur . C'est ce qui distingue fondamentalement le système d'exploitation des autres logiciels système . La partie du système qui s'exécute en mode noyau est appelée noyau du système d'exploitation. Le noyau est conçu comme un logiciel de confiance, ce qui signifie qu'il implémente des mécanismes de protection qui ne peuvent pas être modifiés de manière dissimulée par des logiciels non fiables exécutés en mode utilisateur. Les extensions du système d'exploitation fonctionnent en mode utilisateur , de sorte que les fonctionnalités de base du système d'exploitation ne dépendent pas de ces extensions pour fonctionner correctement.
Une décision de conception clé pour toute fonction du système d'exploitation consiste à déterminer si elle doit être implémentée dans le noyau. Si elle est implémentée dans le noyau, elle fonctionne en mode noyau, accédant à d'autres parties du noyau et étant approuvée par celles-ci. Inversement, si la fonction s'exécute en mode utilisateur , elle n'a pas accès aux structures de données du noyau mais nécessite un effort minimal pour être invoquée. Bien que les fonctions implémentées dans le noyau puissent être simples, le mécanisme de trappe et le processus d'authentification requis pendant l'appel peuvent être relativement gourmands en ressources. Bien que le code du noyau lui-même s'exécute efficacement, la surcharge associée à l'appel peut être importante. Il s'agit d'une distinction subtile mais importante.
Demande de services système
Il existe deux techniques par lesquelles un programme exécuté en mode utilisateur peut demander les services du noyau :
Les systèmes d'exploitation sont conçus avec l'une ou l'autre de ces deux fonctionnalités, mais pas les deux. Tout d'abord, supposons qu'un processus utilisateur souhaite invoquer une fonction système cible particulière. Pour l' approche d'appel système , le processus utilisateur utilise l'instruction trap. L'idée est que l'appel système doit apparaître comme un appel de procédure ordinaire au programme d'application ; le système d'exploitation fournit une bibliothèque de fonctions utilisateur avec des noms correspondant à chaque appel système réel. Chacune de ces fonctions stub contient un trap vers la fonction du système d'exploitation. Lorsque le programme d'application appelle le stub, il exécute l'instruction trap, qui fait passer le processeur en mode noyau , puis se branche (indirectement via une table du système d'exploitation ), au point d'entrée de la fonction qui doit être invoquée. Lorsque la fonction se termine, elle fait passer le processeur en mode utilisateur , puis rend le contrôle au processus utilisateur, simulant ainsi un retour de procédure normal.
Dans l' approche de transmission de messages , le processus utilisateur construit un message qui décrit le service souhaité. Il utilise ensuite une fonction d'envoi fiable pour transmettre le message à un processus OS fiable . La fonction d'envoi remplit le même rôle que l'interruption, c'est-à-dire qu'elle vérifie soigneusement le message, bascule le processeur en mode noyau, puis transmet le message à un processus qui implémente les fonctions cibles. Pendant ce temps, le processus utilisateur attend le résultat de la demande de service avec une opération de réception de message. Lorsque le processus OS termine l'opération, il renvoie un message au processus utilisateur.
La distinction entre les deux approches a des conséquences importantes concernant l'indépendance du comportement du système d'exploitation par rapport au comportement du processus d'application, et les performances qui en résultent. En règle générale, les systèmes d'exploitation basés sur une interface d'appel système peuvent être rendus plus efficaces que ceux nécessitant l'échange de messages entre des processus distincts. C'est le cas même si l'appel système doit être implémenté avec une instruction trap ; c'est-à-dire que même si l'interruption est relativement coûteuse à exécuter, elle est plus efficace que l'approche par transmission de messages, où les coûts associés au multiplexage , à la formation et à la copie des messages sont généralement plus élevés. L'approche par appel système a la propriété intéressante qu'il n'y a pas nécessairement de processus du système d'exploitation. Au lieu de cela, un processus exécuté en mode utilisateur passe en mode noyau lorsqu'il exécute du code noyau, et revient en mode utilisateur lorsqu'il revient de l'appel du système d'exploitation. Si, d'un autre côté, le système d'exploitation est conçu comme un ensemble de processus séparés, il est généralement plus facile de le concevoir de manière à ce qu'il prenne le contrôle de la machine dans des situations particulières, que si le noyau est simplement une collection de fonctions exécutées par des processus utilisateur en mode noyau. Les systèmes d'exploitation basés sur des procédures incluent généralement au moins quelques processus système (appelés démons sous UNIX ) pour gérer les situations dans lesquelles la machine est par ailleurs inactive, comme la planification et la gestion du réseau.