Comment fonctionne dormir un fil?

14

Lorsque vous dormez un fil, que se passe-t-il réellement?

Je vois que dormir un thread "met en pause le thread actuel pendant une période de temps donnée" . Mais comment ça marche?

Selon comment Thread.sleep () fonctionne en interne et comment Thread.sleep fonctionne-t-il vraiment? :

  • la durée du sommeil sera soumise à une granularité spécifique au système
  • le sommeil bloque
  • le thread quitte le CPU et arrête son exécution
  • le thread ne consomme pas de temps CPU pendant le sommeil

Je ne comprends tout simplement pas la mécanique interne et fondamentale de ce que tout cela signifie.

Je comprends qu'il existe quelque chose appelé le planificateur qui est responsable de la commutation entre les threads.

Les sources semblent indiquer que cela varie selon le système d'exploitation (ou le matériel?) Et la plupart des threads disposent de 1 à 60 ms environ pour effectuer certaines actions avant que le processeur ne passe à un autre thread.

Mais lorsqu'un fil dort (par exemple, plusieurs secondes), comment reprend-il? Je suppose qu'une minuterie est impliquée d'une manière ou d'une autre, est-ce l'horloge de la carte mère? Est-ce lié à la fréquence d'horloge du processeur?

Et même si un minuteur est impliqué, comment le CPU sait-il quand il est temps de prêter attention au thread? Ne devrait-il pas constamment vérifier le fil pour voir s'il est prêt? Est -ce pas efficace vote et donc de genre est beaucoup de temps CPU?

Le sommeil est-il spécifique à la langue du thread ou le système d'exploitation en est-il responsable ou est-ce une chose spécifique au CPU?

Quelqu'un pourrait-il m'expliquer cela avec des explications de base sur des choses comme le planificateur et ce que le CPU fait pendant tout cela?

Rowan Freeman
la source
2
L'éveil d'un thread en veille fonctionne à nouveau par des interruptions chronométrées, généralement générées par une horloge d'interruption, qui est un composant matériel distinct de la partie centrale du CPU qui traite les instructions. Cela évite les besoins de sondage. Peut-être que cette explication sur Quora clarifiera certaines choses: quora.com/How-does-threading-work-at-CPU-level
Doc Brown
1
La plupart des JVMs ne fait pas la mise en œuvre multi-threading: Tout ce qu'ils font est d' utiliser les capacités multi-threading du système d'exploitation sous - jacent. Si vous voulez vraiment savoir comment cela fonctionne, il existe de nombreux livres sur le thème de la conception de systèmes d'exploitation.
Solomon Slow

Réponses:

11

L'exécution d'un programme est beaucoup plus impliquée que le simple code de ce programme.

Tout programme qui s'exécute dans un système d'exploitation multi-processus est sous le contrôle du planificateur du système d'exploitation , et le planificateur maintient une table explicite indiquant quel processus est en cours d'exécution, ceux qui attendent de s'exécuter lorsque les cycles du processeur sont disponibles et ceux qui ne sont même pas essayer de courir (dormir). Le planificateur attribue généralement des tranches de temps de taille égale aux processus en fonction de leur priorité et de leur historique d'exécution. En fin de compte, cette boucle est entraînée par des interruptions matérielles, généralement générées par un oscillateur sur la carte principale.

La mise en veille est toujours une fonctionnalité qu'un langage de programmation ne peut prendre en charge que parce que l'environnement d'exécution où il sera exécuté le prend en charge. Un programme normal ne peut pas suspendre lui - même , il ne peut dire le planificateur comment il aime à traiter - et le planificateur est nullement obligé ou même toujours capables de satisfaire ce souhait. Pensez à un ordinateur portable fermé et en veille prolongée; l'oscillateur de la carte principale continue de pulser, mais comme le planificateur n'est pas en cours d'exécution, aucun processus ne peut être exécuté, quelle que soit sa priorité.

Kilian Foth
la source
Cela est (généralement) vrai pour les processus, mais pas toujours pour les threads, qui dépendent parfois de la langue. Les threads peuvent être implémentés indépendamment du système d'exploitation et peuvent être coopératifs ou préemptifs. Par exemple, Ruby a des "fibres" (en plus des fils). Les fibres de rubis sont programmées en coopération.
david25272
Certes, seuls les threads natifs fonctionnent comme ça. Les threads verts sont planifiés par la machine virtuelle exécutant un programme dans un langage compilé en octets. Habituellement, ils sont utilisés lorsque les threads natifs ne sont pas disponibles, ou lors de l'exécution de code qui n'est pas correctement thread-safe (la machine virtuelle peut parfois garantir que la sémantique d'un programme multithread reste correcte d'une manière que le planificateur du système d'exploitation ne peut pas).
Kilian Foth
7

Comme Doc Brown l'a mentionné dans un commentaire, les interruptions sont la clé, et pas seulement pour dormir.

Une interruption est un signal matériel que le processeur doit arrêter ce qu'il fait et exécuter un morceau de code. Les périphériques externes déclenchent des interruptions lorsqu'ils nécessitent l'attention du processeur: par exemple, lorsqu'un disque a fini de lire les données, ou qu'une touche a été enfoncée, ou qu'un compte à rebours sur la carte mère a atteint zéro.

Le code de gestion des interruptions est généralement très petit et très rapide. Par exemple, lorsque le disque indique qu'un bloc a été copié en mémoire, le système d'exploitation peut simplement enregistrer ce fait dans une liste de "blocs prêts" quelque part, puis revenir à tout ce qu'il faisait. Vous ne voulez pas que le CPU passe tout son temps dans le code de gestion des interruptions et n'exécute pas le code utilisateur.

Un élément de code piloté par interruption qui n'est pas nécessairement petit est le planificateur. Il est déclenché par un signal provenant d'un compte à rebours et examine l'état du système chaque fois qu'il est exécuté. Cela comprend généralement l'identification des processus prêts à être exécutés (par exemple, parce que le bloc qu'ils attendaient est arrivé en mémoire), ainsi que ceux qui ont épuisé leur tranche de temps.

Ainsi, lorsque vous exécutez une veille de thread, ce que vous faites est de dire au système d'exploitation que (1) vous abandonnez votre tranche de temps, et (2) vous ne devriez pas être réveillé à nouveau jusqu'à ce qu'un certain temps se soit écoulé.

Chaque fois que le planificateur s'exécute, il examine votre thread et le marque comme «prêt à fonctionner» uniquement si ce temps s'est écoulé. C'est une interrogation, en quelque sorte, mais ce n'est pas une interrogation "en boucle occupée" car elle est déclenchée par une interruption. Ce n'est pas non plus si cher: généralement, il n'y a qu'un millier de threads à la fois.

Cela devrait également vous donner une idée des raisons pour lesquelles les temps de veille ne sont pas exacts: lorsque votre thread est prêt à fonctionner, il peut y avoir d'autres threads qui sont toujours en cours d'exécution et n'ont pas épuisé leur tranche de temps. Ou il peut y avoir des threads de priorité supérieure qui sont prêts à s'exécuter.

kdgregory
la source
C'est ainsi que fonctionnent les systèmes d'exploitation "modernes". Dans les anciens systèmes d'exploitation, tels que Windows 3 ou Mac OS avant OS X, un processus devait céder le contrôle () au système d'exploitation. Malheureusement, si un programme était coincé dans une boucle ou bloqué d'une manière ou d'une autre, il pourrait ne jamais céder le contrôle et le système entier se bloquerait.
david25272
@ david25272 - Je pense que j'utiliserais le mot "plus simple" que "plus ancien", car il y avait des systèmes des années 60 qui faisaient du multitâche préemptif. Et bien qu'il soit vrai que le multitâche coopératif nécessite que le thread actif fasse quelque chose pour libérer son contrôle du processeur (généralement en faisant un appel système de blocage, plutôt qu'un rendement explicite), je ne pense pas qu'il existe de nombreux programmeurs à usage général aujourd'hui qui utilisent un OS avec un modèle de thread coopératif.
kdgregory