web-dev-qa-db-fra.com

Étapes de la commutation de contexte

On me demande de décrire les étapes impliquées dans un changement de contexte (1) entre deux processus différents et (2) entre deux threads différents dans le même processus.

  1. Lors d'un changement de contexte, le noyau enregistre le contexte de l'ancien processus dans son PCB puis charge le contexte enregistré du nouveau processus prévu pour s'exécuter.
  2. La commutation de contexte entre deux threads différents dans le même processus peut être planifiée par le système d'exploitation afin qu'ils semblent s'exécuter en parallèle, et est donc généralement plus rapide que les changements de contexte entre deux processus différents.

Est-ce trop général ou qu'apporteriez-vous pour expliquer le processus plus clairement?

38
raphnguyen

Il est beaucoup plus facile d'expliquer ceux-ci dans l'ordre inverse, car un commutateur de processus implique toujours un commutateur de thread.

Un changement de contexte de thread typique sur un processeur monocœur se produit comme ceci:

  1. Tous les changements de contexte sont déclenchés par une "interruption". Il peut s'agir d'une interruption matérielle réelle qui exécute un pilote (par exemple, à partir d'une carte réseau, d'un clavier, de la gestion de la mémoire ou du matériel du minuteur) ou d'un appel logiciel (appel système) qui exécute une séquence d'appels de type interruption matérielle pour entrer dans l'OS. Dans le cas d'une interruption du pilote, le système d'exploitation fournit un point d'entrée que le pilote peut appeler au lieu d'effectuer le retour d'interruption direct `` normal '' et permet ainsi à un pilote de quitter via le planificateur du système d'exploitation s'il a besoin du système d'exploitation pour définir un thread prêt, (par exemple, il a signalé un sémaphore).

  2. Les systèmes non triviaux devront initier un changement de niveau de protection du matériel pour entrer dans un état du noyau afin que le code/les données du noyau, etc. soient accessibles.

  3. L'état de base du thread interrompu doit être enregistré. Sur un système embarqué simple, cela pourrait simplement pousser tous les registres sur la pile de threads et enregistrer le pointeur de pile dans son bloc de contrôle des threads (TCB).

  4. De nombreux systèmes passent à une pile dédiée au système d'exploitation à ce stade afin que la majeure partie des exigences de la pile interne au système d'exploitation ne soient pas infligées à la pile de chaque thread.

  5. Il peut être nécessaire de marquer la position de la pile de threads où le changement d'état d'interruption s'est produit pour permettre les interruptions imbriquées.

  6. L'appel du pilote/système s'exécute et peut modifier l'ensemble de threads prêts en ajoutant/supprimant des TCB des files d'attente internes pour les différentes priorités de thread, par exemple. le pilote de carte réseau peut avoir défini un événement ou signalé un sémaphore qu'un autre thread attendait, de sorte que le thread sera ajouté à l'ensemble prêt, ou un thread en cours d'exécution peut avoir appelé sleep () et ainsi choisi de se retirer de l'ensemble prêt .

  7. L'algorithme du planificateur du système d'exploitation est exécuté pour décider quel thread exécuter ensuite, généralement le thread prêt de priorité la plus élevée qui se trouve à l'avant de la file d'attente pour cette priorité. Si le thread suivant doit appartenir à un processus différent du thread précédemment exécuté, des éléments supplémentaires sont nécessaires ici (voir plus loin).

  8. Le pointeur de pile enregistré à partir du TCB pour ce thread est récupéré et chargé dans le pointeur de pile matériel.

  9. L'état de base du thread sélectionné est restauré. Sur mon système simple, les registres seraient extraits de la pile du thread sélectionné. Les systèmes plus complexes devront gérer un retour à la protection au niveau de l'utilisateur.

  10. Un retour d'interruption est effectué, transférant ainsi l'exécution au thread sélectionné.

Dans le cas d'un processeur multicœur, les choses sont plus complexes. Le planificateur peut décider qu'un thread qui s'exécute actuellement sur un autre noyau peut devoir être arrêté et remplacé par un thread qui vient d'être prêt. Il peut le faire en utilisant son pilote interprocesseur pour interrompre matériellement le noyau exécutant le thread qui doit être arrêté. La complexité de cette opération, en plus de toutes les autres choses, est une bonne raison pour éviter d'écrire des noyaux de système d'exploitation :)

Un changement de contexte de processus typique se produit comme ceci:

  1. Les changements de contexte de processus sont initiés par un changement de contexte de thread, donc tout ce qui précède, 1-9, devra se produire.

  2. À l'étape 5 ci-dessus, le planificateur décide d'exécuter un thread appartenant à un processus différent de celui qui possédait le thread précédemment exécuté.

  3. Le matériel de gestion de la mémoire doit être chargé avec l'espace d'adressage pour le nouveau processus, c'est-à-dire quels que soient les sélecteurs/segments/drapeaux/tout ce qui permet au thread/s du nouveau processus d'accéder à sa mémoire.

  4. Le contexte de tout matériel FPU doit être enregistré/restauré à partir du PCB.

  5. Il peut y avoir un autre matériel dédié au processus qui doit être enregistré/restauré.

Sur tout système réel, les mécanismes dépendent de l'architecture et ce qui précède est un guide approximatif et incomplet des implications de chaque changement de contexte. Il y a d'autres frais généraux générés par un commutateur de processus qui ne font pas strictement partie du commutateur - il peut y avoir des vidages de cache supplémentaires et des défauts de page après un commutateur de processus car une partie de sa mémoire peut avoir été paginée en faveur des pages appartenant au processus propriétaire du thread qui s'exécutait auparavant.

62
Martin James

J'espère que je pourrai fournir une image plus détaillée/claire.

Tout d'abord, le système d'exploitation planifie les threads, pas les processus, car les threads sont les seules unités exécutables du système. Le commutateur de processus est juste un commutateur de threads où les threads appartiennent à différents processus, et donc la procédure est fondamentalement la même.

  1. Le planificateur est appelé. Il existe trois scénarios de base dans lesquels cela peut se produire:

    • Changement involontaire. Un événement externe affectant la planification s'est produit en dehors du thread en cours d'exécution. Par exemple, un minuteur expiré a réveillé un thread avec une priorité élevée; ou le contrôleur de disque a signalé que la partie demandée d'un fichier a été lue dans la mémoire et que le thread en attente peut continuer son exécution; ou le temporisateur système a indiqué au noyau que votre thread n'avait plus de temps quantique; etc.
    • Changement volontaire. Le thread demande explicitement une replanification via un appel système. Par exemple, il peut avoir demandé de céder le CPU à un autre thread, de l'endormir ou d'attendre la libération d'un mutex.
    • Changement semi-volontaire. Le thread a implicitement déclenché une replanification en effectuant un appel système non lié. Par exemple, il a demandé de lire un fichier. Le système d'exploitation a transmis cette demande au contrôleur de disque, et pour ne pas perdre de temps en ayant le thread appelant occupé à attendre, il a décidé de passer à un autre thread.
  2. Dans tous les cas, pour pouvoir effectuer un changement de contexte, le contrôle doit être passé au noyau. Dans le cas de commutations involontaires, ceci est effectué par une interruption. Dans le cas des changements de contexte volontaires (et semi-volontaires), le contrôle est transmis au noyau via un appel système.

  3. Dans les deux cas, l'entrée du noyau est assistée par CPU. Le processeur effectue une vérification des autorisations, enregistre le pointeur d'instruction (afin que l'exécution puisse être poursuivie à partir de la bonne instruction plus tard), passe du mode utilisateur utilisateur au mode noyau, active la pile du noyau (spécifique au thread actuel) et passe à un paramètre prédéfini et point bien connu dans le code du noyau.

  4. La première action effectuée par le noyau est la sauvegarde du contenu des registres CPU, qu'il doit utiliser à ses propres fins. Habituellement, le noyau utilise uniquement des registres CPU à usage général et les enregistre en les poussant sur la pile.

  5. Le noyau gère ensuite une requête principale si nécessaire. Il peut gérer une interruption, préparer une demande de lecture de fichier, recharger une minuterie, etc.

  6. À un certain moment pendant la gestion des demandes, le noyau effectue une action qui affecte l'état du thread actuel (a décidé qu'il n'y a actuellement rien à faire dans ce thread car il attend quelque chose) ou celui d'un autre thread (ou threads) (un thread est devenu prêt à s'exécuter car un événement qu'il attendait s'est produit - un mutex a été libéré, par exemple).

  7. Le noyau appelle le planificateur. L'ordonnanceur doit prendre deux décisions.

    • Que faire avec le fil actuel? Doit-il être bloqué? Si oui, dans quelle file d'attente doit-elle être placée? Si le commutateur est involontaire, il est placé à la fin de la file d'attente prête. Sinon, le thread est placé dans l'une des files d'attente.
    • Quel thread doit être exécuté ensuite?
  8. Une fois les deux décisions prises, le planificateur effectue le changement de contexte en utilisant le TCB du thread en cours ainsi que celui du thread qui doit être exécuté ensuite.

  9. Un changement de contexte lui-même comprend trois étapes principales.

    • Le noyau détermine quel CPU enregistre le thread utilise réellement et enregistre leur contenu sur la pile ou dans le TCB du thread non planifié. Dans le cas de la plate-forme CPU IA-32, si le thread n'utilise pas FPU et SSE registres, leur contenu ne sera pas enregistré.
    • Le noyau pousse le pointeur d'instruction sur la pile et enregistre la valeur du pointeur de pile dans le TCB du thread non planifié. Il charge ensuite le pointeur de pile à partir du TCB du thread planifié et fait apparaître le pointeur d'instruction du haut de sa pile.
    • Le noyau détermine quels registres sont réellement utilisés par le thread planifié et les charge avec leur contenu précédemment stocké (voir l'étape 1 ci-dessus).
  10. À ce stade, le noyau vérifie si les threads planifiés et non planifiés appartiennent au même processus. Sinon (commutateur "processus" plutôt que "thread"), le noyau réinitialise l'espace d'adressage actuel en pointant le MMU (unité de gestion de la mémoire) vers la table des pages du processus planifié. Le TLB (Translation Lookaside Buffer), qui est un cache contenant les récentes traductions d'adresses virtuelles en adresses physiques, est également vidé pour éviter une traduction d'adresse erronée. Notez que c'est la seule étape de l'ensemble des actions de changement de contexte qui se soucie des processus!

  11. Le noyau prépare le stockage local de threads pour le thread planifié. Par exemple, il mappe les pages de mémoire respectives aux adresses spécifiées. Comme autre exemple, sur la plate-forme IA-32, une approche courante consiste à charger un nouveau segment qui pointe vers les données TLS du thread entrant.

  12. Le noyau charge l'adresse de pile de noyau du thread actuel dans le CPU. Après cela, chaque invocation du noyau utilisera cette pile de noyau au lieu de la pile de noyau du thread non planifié.

  13. Une autre étape qui peut être effectuée par le noyau est la reprogrammation du temporisateur système. Lorsque le minuteur se déclenche, le contrôle est retourné au noyau. La période de temps entre le changement de contexte et le déclenchement de la minuterie est appelée un quantum de temps et indique la durée d'exécution du thread actuel à ce moment. Ceci est connu sous le nom de planification préventive.

  14. Les noyaux collectent généralement des statistiques lors des changements de contexte pour améliorer la planification ainsi que pour montrer aux administrateurs système et aux utilisateurs ce qui se passe dans le système. Ces statistiques peuvent inclure des informations telles que le temps processeur consommé par le thread, le nombre de fois qu'il a été planifié, le nombre de fois que son quantum a expiré, la fréquence à laquelle les changements de contexte se produisent dans le système, etc.

  15. Le changement de contexte peut être considéré comme prêt à ce stade, et le noyau continue les actions système précédemment interrompues. Par exemple, si le thread a tenté d'acquérir un mutex lors d'un appel système et que le mutex est désormais libre, le noyau peut terminer l'opération interrompue.

  16. À un moment donné, le thread termine ses activités système et souhaite revenir en mode utilisateur pour exécuter du code non système. Le noyau apparaît à partir du contenu de la pile du noyau des registres à usage général qui a été précédemment enregistré lors de l'entrée du noyau et oblige le CPU à exécuter une instruction spéciale pour revenir en mode utilisateur.

  17. Le CPU capture les valeurs du pointeur d'instruction et du pointeur de pile, qui étaient précédemment enregistrés, le mode noyau a été entré et les restaure. À ce stade, la pile du mode utilisateur du thread est également activée et le mode noyau est quitté (cela interdit l'utilisation d'instructions système spéciales).

  18. Enfin, le processeur continue son exécution à partir du point où se trouvait le thread lorsqu'il n'a pas été planifié. Si cela s'est produit pendant un clal système, le thread procédera à partir du point où l'appel système a été appelé, en capturant et en gérant son résultat. En cas de préemption par interruption, le thread continuera son exécution comme si de rien n'était.

Quelques notes de synthèse:

  1. Le noyau planifie et exécute uniquement les threads, pas les processus - les changements de contexte ont lieu entre les threads.

  2. La procédure de basculement vers le contexte d'un thread d'un autre processus est essentiellement la même dans un changement de contexte entre des threads appartenant au même processus. Une seule étape supplémentaire est requise: changer les tables de pages (et vider le TLB).

  3. Le contexte du thread est stocké soit dans la pile du noyau, soit dans le TCB (pas PCB!).

  4. La commutation de contexte est une opération coûteuse - elle a un coût direct significatif en termes de performances, et le coût indirect provoqué par la pollution du cache (et le vidage TLB si le changement s'est produit entre les processus) est encore plus élevé.

17
ZarathustrA
  1. Dans un commutateur, l'état du processus en cours d'exécution doit être enregistré d'une manière ou d'une autre, de sorte que lorsqu'il est replanifié, cet état puisse être restauré.
  2. L'état du processus comprend tous les registres que le processus peut utiliser, en particulier le compteur de programme, ainsi que toutes les autres données spécifiques au système d'exploitation qui peuvent être nécessaires. Ceci est généralement stocké dans une structure de données appelée bloc de contrôle de processus (PCB) ou cadre de commutation.
  3. Le PCB peut être stocké sur une pile par processus dans la mémoire du noyau (par opposition à la pile d'appels en mode utilisateur), ou il peut y avoir une structure de données définie par le système d'exploitation spécifique pour ces informations. Un handle vers le PCB est ajouté à une file d'attente de processus prêts à être exécutés, souvent appelée file d'attente prête.
  4. Étant donné que le système d'exploitation a effectivement suspendu l'exécution d'un processus, il peut alors changer de contexte en choisissant un processus dans la file d'attente prête et en restaurant son PCB. Ce faisant, le compteur de programme du PCB est chargé, et donc l'exécution peut continuer dans le processus choisi. La priorité du processus et du thread peut influencer le processus choisi dans la file d'attente prête (c'est-à-dire, il peut être une file d'attente prioritaire).

Context Switch

(Source: changement de contexte )

1.Enregistrez le contexte du processus en cours d'exécution sur la CPU. Mettez à jour le bloc de contrôle de processus et d'autres champs importants.

2. Déplacez le bloc de contrôle de processus du processus ci-dessus dans la file d'attente appropriée telle que la file d'attente prête, la file d'attente d'E/S, etc.

3.Sélectionnez un nouveau processus d'exécution.

4.Mettez à jour le bloc de contrôle de processus du processus sélectionné. Cela inclut la mise à jour de l'état du processus en cours d'exécution.

5.Mettez à jour les structures de données de gestion de la mémoire selon les besoins.

6. Restaurez le contexte du processus qui s'exécutait précédemment lorsqu'il est à nouveau chargé sur le processeur. Cela se fait en chargeant les valeurs précédentes du bloc de contrôle de processus et des registres.

0
red_herring