J'ai parcouru quelques notes basées sur ce sujet, et bien que je comprenne les threads en général, je ne suis pas vraiment sûr de la différences entre les threads de niveau utilisateur et ceux de niveau noya =.
Je sais que les processus sont essentiellement constitués de plusieurs threads ou d'un seul thread, mais ces threads appartiennent-ils aux deux types mentionnés précédemment?
D'après ce que j'ai compris, les threads pris en charge par le noyau ont accès au noyau pour les appels système et autres utilisations non disponibles pour les threads au niveau utilisateur.
Ainsi, les threads de niveau utilisateur sont-ils simplement des threads créés par le programmeur lorsqu'ils utilisent ensuite des threads pris en charge par le noyau pour effectuer des opérations qui ne pourraient pas être effectuées normalement en raison de son état?
Edit: La question était un peu déroutante, alors je réponds de deux manières différentes.
Par souci de clarté, je dis habituellement "threads au niveau du système d'exploitation" ou "threads natifs" au lieu de "threads au niveau du noyau" (ce que j'ai confondu avec les "threads du noyau" dans ma réponse originale ci-dessous.) Les threads au niveau du système d'exploitation sont créés et gérés par l'OS. La plupart des langues sont prises en charge. (C, Java récent, etc.) Ils sont extrêmement difficiles à utiliser car vous êtes entièrement responsable de la prévention des problèmes. Dans certaines langues, même les structures de données natives (telles que les hachages ou les dictionnaires) se briseront sans code de verrouillage supplémentaire.
L'opposé d'un OS-thread est un fil vert qui est géré par votre langue. Ces threads portent différents noms en fonction de la langue (coroutines en C, goroutines en Go, fibres en Ruby, etc.). Ces fils n'existent que dans votre langue et pas dans votre système d'exploitation. Du fait que la langue choisit les changements de contexte (c'est-à-dire à la fin d'une instruction), elle empêche TONS de conditions de concurrence subtiles (telles que l'affichage d'une structure partiellement copiée ou le besoin de verrouiller la plupart des structures de données). Le programmeur voit les appels "bloquants" (c'est-à-dire data = file.read()
), mais la langue le traduit en appels asynchrones vers le système d'exploitation. Le langage permet alors à autre des threads verts de s'exécuter en attendant le résultat.
Les threads verts sont beaucoup plus simples pour le programmeur, mais leurs performances varient: si vous avez BEAUCOUP de threads, les threads verts peuvent être meilleurs pour le processeur et la RAM. D'un autre côté, la plupart des langages de threads verts ne peuvent pas tirer parti de plusieurs cœurs. (Vous ne pouvez même plus acheter un ordinateur mono-core ou un téléphone!). Et une mauvaise bibliothèque peut interrompre l’ensemble de la langue en bloquant un appel à un système d’exploitation.
Le meilleur des deux mondes est d'avoir un thread de système d'exploitation par processeur et de nombreux threads verts qui sont déplacés par magie sur des threads de système d'exploitation. Des langues comme Go et Erlang peuvent le faire.
appels système et autres utilisations non disponibles pour les threads au niveau utilisateur
Ce n'est qu'à moitié vrai. Oui, vous pouvez facilement causer des problèmes si vous appelez le système d’exploitation vous-même (c’est-à-dire faites quelque chose qui bloque.) Mais la langue a généralement des remplacements, vous ne le remarquez donc pas. Ces remplacements appellent le noyau, légèrement différemment que vous ne le pensez.
Edit: C’est ma réponse originale, mais il s’agit des threads de l’espace utilisateur et des threads ne contenant que du noyau, ce qui (avec le recul) n’était probablement pas la question
Les threads utilisateur et les threads du noyau sont exactement les mêmes. (Vous pouvez voir en regardant dans/proc/et voir que les threads du noyau sont là aussi.)
Un thread utilisateur est celui qui exécute le code d'espace utilisateur. Mais il peut appeler dans le noyau à tout moment. Il est toujours considéré comme un fil "utilisateur", même s'il exécute du code du noyau à des niveaux de sécurité élevés.
Un thread de noyau est un thread qui exécute uniquement le code du noyau et n'est pas associé à un processus d'espace utilisateur. Ils ressemblent à des "démons UNIX", à la différence qu’ils ne sont que des démons du noyau. On pourrait donc dire que le noyau est un programme multi-threadé. Par exemple, il existe un thread de noyau pour le swap. Cela oblige tous les problèmes de swap à se "sérialiser" dans un seul flux.
Si un thread utilisateur a besoin de quelque chose, il fera appel au noyau, ce qui le marque comme étant en veille. Plus tard, le thread d'échange trouve les données et le marque donc comme exécutable. Plus tard encore, le "thread utilisateur" retourne du noyau à userland comme si rien ne s'était passé.
En fait, les threads tous démarrent dans l'espace du noyau, car l'opération clone () se déroule dans l'espace du noyau. (Et il y a beaucoup de comptabilité de noyau à faire avant de pouvoir "retourner" à un nouveau processus dans l'espace utilisateur.)
Avant de commencer la comparaison, comprenons d'abord ce qu'est un fil. Les threads sont des processus légers dans le domaine des processus indépendants. Ils sont nécessaires car les processus sont lourds, consomment beaucoup de ressources et, plus important encore,
deux processus distincts ne peuvent pas partager un espace mémoire.
Disons que vous ouvrez un éditeur de texte. C'est un processus indépendant qui s'exécute dans la mémoire avec un emplacement adressable distinct. Ce processus nécessite de nombreuses ressources, telles que l'insertion de graphiques, la vérification orthographique, etc. Il est impossible de créer des processus distincts pour chacune de ces fonctionnalités et de les conserver indépendamment en mémoire. Pour éviter cela,
plusieurs threads peuvent être créés au sein d'un même processus, pouvant ainsi partager un espace mémoire commun, existant indépendamment au sein d'un processus.
Revenons maintenant à vos questions, une à la fois.
Je ne suis pas vraiment sûr de la différence entre les threads au niveau utilisateur et au niveau noyau.
Les threads sont généralement classés comme au niveau utilisateur et au niveau du noyau en fonction de leur domaine d'exécution. Il existe également des cas où un ou plusieurs threads utilisateur sont mappés sur un ou plusieurs threads du noyau .
- Threads de niveau utilisateur
Les threads au niveau utilisateur se situent principalement au niveau de l'application où une application les crée pour maintenir son exécution dans la mémoire principale. Sauf si requis, ces threads fonctionnent de manière isolée avec les threads du noyau.
Celles-ci sont plus faciles à créer car ils ne doivent pas nécessairement faire référence à de nombreux registres et le changement de contexte est beaucoup plus rapide qu'un thread au niveau du noyau.
Un thread au niveau utilisateur peut généralement entraîner des modifications au niveau de l'application et le thread au niveau du noyau continue de s'exécuter à son rythme.
- Threads au niveau du noya
Ces threads sont généralement indépendants des processus en cours et sont exécutés par le système d'exploitation.
Le système d'exploitation a besoin de ces threads pour des tâches telles que la gestion de la mémoire, la gestion des processus, etc.
Puisque ces threads maintiennent, exécutent et rapportent les processus requis par le système d'exploitation; les threads au niveau du noyau sont plus coûteux à créer et à gérer et la commutation de contexte de ces threads est lente.
La plupart des threads de niveau noyau ne peuvent pas être préemptés par les threads de niveau utilisateur.
MS DOS written for Intel 8088 didn't have dual mode of operation. Thus, a user level process had the ability to corrupt the entire operating system.
- Threads de niveau utilisateur mappés sur des threads du noya
C'est peut-être la partie la plus intéressante. De nombreux threads au niveau utilisateur se connectent au thread au niveau du noyau, qui communique à son tour avec le noyau.
Voici quelques exemples de mappages importants:
Un par un
Lorsqu'un thread de niveau utilisateur est mappé à un seul thread du noyau.
avantages: chaque thread utilisateur correspond à un thread du noyau. Même si l'un des threads utilisateur émet un appel système bloquant, les autres processus ne sont pas affectés.
inconvénients: chaque thread utilisateur nécessite un thread du noyau pour interagir et sa création et sa gestion sont coûteuses.
Plusieurs à un
Lorsque plusieurs threads utilisateurs sont mappés sur un thread du noyau.
avantages: plusieurs threads du noyau ne sont pas nécessaires car des threads utilisateur similaires peuvent être mappés à un thread du noyau.
inconvénient: même si l'un des threads utilisateur émet un appel système bloquant, tous les autres threads utilisateur mappés sur ce thread du noyau sont bloqués.
En outre, un bon niveau de concurrence ne peut pas être atteint car le noyau ne traitera qu'un seul thread à la fois.
Plusieurs à plusieurs
Lorsque plusieurs threads utilisateurs sont mappés sur un nombre égal ou inférieur de threads du noyau. Le programmeur décide du nombre de threads utilisateur mappés sur le nombre de threads du noyau. Certains des threads utilisateur peuvent mapper à un seul thread du noyau.
avantages: un grand niveau de simultanéité est atteint. Le programmeur peut choisir des threads potentiellement dangereux pouvant émettre un appel système bloquant et les placer avec le mappage un à un.
inconvénient: le nombre de threads du noyau, s'il n'est pas décidé avec prudence, peut ralentir le système.
L'autre partie de votre question:
les threads pris en charge par le noyau ont accès au noyau pour les appels système et d'autres utilisations non disponibles pour les threads au niveau utilisateur.
Ainsi, les threads de niveau utilisateur sont-ils simplement des threads créés par le programmeur lorsqu'ils utilisent ensuite des threads pris en charge par le noyau pour effectuer des opérations qui ne pourraient pas être effectuées normalement en raison de son état?
Partiellement correct. Presque tous les threads du noyau ont accès aux appels système et à d'autres interruptions critiques puisque les threads du noyau sont responsables de l'exécution des processus du système d'exploitation. Le fil utilisateur n'aura pas accès à certaines de ces fonctionnalités critiques. par exemple. un éditeur de texte ne peut jamais tirer sur un fil capable de modifier l'adresse physique du processus. Toutefois, si nécessaire, un thread utilisateur peut mapper sur le thread du noyau et émettre certains des appels système, ce qu’il ne pourrait pas faire en tant qu’entité indépendante. Le thread du noyau mapperait alors cet appel système sur le noyau et exécuterait des actions, s'il le jugeait utile.
Certains environnements ou langages de développement ajouteront leurs propres threads, comme une fonctionnalité, écrite pour tirer parti de certaines connaissances de l'environnement. Par exemple, un environnement graphique peut implémenter des fonctionnalités de thread permettant de basculer entre les threads utilisateur de chaque boucle d'événement. Une bibliothèque de jeux peut avoir un comportement semblable à celui des personnages. Parfois, le comportement semblable à un fil utilisateur peut être mis en œuvre de manière différente, par exemple, je travaille beaucoup avec cacao, et il dispose d'un mécanisme de minuterie qui exécute votre code toutes les x secondes, utilise une fraction de seconde et ressemble à un fil. Ruby a une fonctionnalité de rendement qui s'apparente à des threads coopératifs. L'avantage des threads utilisateur est qu'ils peuvent basculer à des moments plus prévisibles. Avec un thread du noyau à chaque démarrage d'un thread, il doit charger les données sur lesquelles il travaillait peuvent prendre un certain temps, avec des threads utilisateur que vous pouvez basculer lorsque vous avez fini de travailler sur certaines données, de sorte qu'elles n'ont pas besoin d'être rechargées. Je n'ai pas rencontré de threads utilisateur qui ressemblent au noyau threads, seulement des mécanismes similaires à ceux du minuteur, bien que j'en ai déjà entendu parler dans des manuels plus anciens, alors je me demande s'ils étaient plus populaires dans le passé, mais avec l'apparition de véritables systèmes d'exploitation multithread (Windows et Mac OS X modernes) et du matériel plus puissant, je me demande s’ils ne sont plus en faveur.
ser-Threads
Kernel-Threads
threads utilisateur: 1. La bibliothèque prend en charge la création, la planification et la gestion des threads sans le support du noyau. 2. Le noyau ignorant la création et la planification de threads au niveau utilisateur se fait dans l'espace utilisateur sans intervention du noyau. 3. Les threads au niveau utilisateur sont généralement rapides à créer et à gérer, ils présentent toutefois des inconvénients. 4. Si le noyau est à thread unique, alors tout thread au niveau utilisateur effectuant un appel système bloquant provoquera le blocage de l'ensemble du processus, même si d'autres threads sont disponibles pour s'exécuter dans l'application. 5. Les bibliothèques de threads utilisateurs incluent les Pthreads POSIX, les C-threads Mach et les UI-threads Solaris 2.
Fils du noyau: 1. Le noyau effectue la création, la planification et la gestion des fils dans l'espace du noyau. 2. Les threads du noyau sont généralement plus lents à créer et à gérer que les threads utilisateurs. 3. le noyau gère les threads, si un thread effectue un appel système bloquant. 4. Dans un environnement multiprocesseur, le noyau peut planifier des threads sur différents processeurs. 5.y compris les threads du noyau prenant en charge Windows NT, Windows 2000, Solaris 2, BeOS et Tru64 UNIX (anciennement Digital UN1X).