90 votes

Différence entre les threads de niveau utilisateur et ceux supportés par le noyau ?

J'ai parcouru quelques notes basées sur ce sujet, et bien que je comprenne les fils en général, je ne suis pas vraiment sûr de la façon dont les fils sont utilisés. différences entre les threads de niveau utilisateur et de niveau noyau .

Je sais que les processus sont essentiellement constitués de plusieurs fils ou d'un seul fil, mais ces fils sont-ils des deux types mentionnés précédemment ?

D'après ce que j'ai compris, les threads supportés par le noyau ont accès au noyau pour les appels système et d'autres utilisations non disponibles pour les threads de niveau utilisateur.

Donc, les threads de niveau utilisateur sont simplement des threads créés par le programmeur qui utilisent ensuite les threads supportés par le noyau pour effectuer des opérations qui ne pourraient pas être normalement effectuées en raison de son état ?

117voto

BraveNewCurrency Points 4096

Edit : La question était un peu confuse, je vais donc y répondre de deux manières différentes.

threads au niveau du système d'exploitation et threads verts

Pour plus de clarté, je dis généralement "threads de niveau OS" ou "threads natifs" au lieu de "threads de niveau noyau" (que j'ai confondu avec "threads du noyau" dans ma réponse originale ci-dessous). Les threads de niveau OS sont créés et gérés par le système d'exploitation. La plupart des langages les prennent en charge. (C, Java récent, etc.) Ils sont extrêmement difficiles à utiliser car vous êtes 100% responsable de la prévention des problèmes. Dans certains langages, même les structures de données natives (comme 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 des noms différents selon le langage (coroutines en C, goroutines en Go, fibers en Ruby, etc). Ces threads n'existent que dans votre langage et non dans votre système d'exploitation. Parce que le langage choisit des commutateurs de contexte (c'est-à-dire à la fin d'une déclaration), il empêche des tonnes de conditions de course subtiles (comme voir une structure partiellement copiée, ou avoir besoin de verrouiller la plupart des structures de données). Le programmeur voit les appels "bloquants" (c'est-à-dire les appels de type data = file.read() ), mais le langage le traduit en appels asynchrones au système d'exploitation. Le langage permet alors autre des threads verts à exécuter en attendant le résultat.

Les threads verts sont beaucoup plus simples pour le programmeur, mais leurs performances sont variables : Si vous avez BEAUCOUP de threads, les green threads peuvent être meilleurs pour le CPU et la RAM. D'autre part, la plupart des langages de threads verts ne peuvent pas tirer parti de plusieurs cœurs. (Il n'est même plus possible d'acheter un ordinateur ou un téléphone à cœur unique). Et une mauvaise bibliothèque peut arrêter le langage entier en faisant un appel bloquant au système d'exploitation.

Le meilleur des deux mondes est d'avoir un thread OS par CPU, et de nombreux threads verts qui sont magiquement déplacés sur les threads OS. Des langages comme Go et Erlang peuvent le faire.

les appels système et autres utilisations non disponibles pour les threads de 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 si vous faites quelque chose qui est bloquant), mais le langage a généralement des remplacements, de sorte que vous ne le remarquez même pas. Ces remplacements font appel au noyau, mais de façon légèrement différente de ce que vous pensez.


Threads du noyau et threads de l'utilisateur

Edit : C'est ma réponse originale, mais elle concerne les threads de l'espace utilisateur par rapport aux threads du noyau uniquement, ce qui (avec du recul) n'était probablement pas la question.

Les threads de l'utilisateur et les threads du noyau sont exactement les mêmes. (Vous pouvez le constater en regardant dans /proc/ et voir que les threads du noyau sont là aussi).

Un thread utilisateur est un thread qui exécute du code en espace utilisateur. Mais il peut faire appel à l'espace noyau à tout moment. Il est toujours considéré comme un thread "utilisateur", même s'il exécute du code noyau à des niveaux de sécurité élevés.

Un thread de noyau est un thread qui n'exécute que le code du noyau et n'est pas associé à un processus de l'espace utilisateur. Ils sont comme des "démons UNIX", sauf qu'ils ne sont que des démons du noyau. On peut donc dire que le noyau est un programme multithread. Par exemple, il existe un thread noyau pour le swap. Cela force tous les problèmes de swap à être "sérialisés" en un seul flux.

Si un thread utilisateur a besoin de quelque chose, il appelle le noyau, qui marque ce thread comme dormant. Plus tard, le thread d'échange trouve les données et marque le thread utilisateur comme étant exécutable. Plus tard encore, le "user thread" revient du noyau vers l'espace utilisateur comme si de rien n'était.

En fait, tous Les threads démarrent dans l'espace noyau, car l'opération clone() se déroule dans l'espace noyau. (Et il y a beaucoup de comptabilité du noyau à faire avant de pouvoir "retourner" à un nouveau processus dans l'espace utilisateur).

29voto

Yusuf Hassan Points 1243

Avant d'entrer dans 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 parce que 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. Vous aurez besoin de nombreuses ressources dans ce processus, comme l'insertion de graphiques, la vérification de l'orthographe, etc. Il n'est pas possible de créer des processus distincts pour chacune de ces fonctionnalités et de les maintenir indépendamment en mémoire. Pour éviter cela,

plusieurs threads peuvent être créés au sein d'un même processus, qui peuvent partager un espace mémoire commun, tout en existant indépendamment au sein d'un processus.

Maintenant, revenons à vos questions, une par une.

Je ne suis pas vraiment sûr des différences entre les threads de niveau utilisateur et de niveau noyau.

Les fils sont classés en deux grandes catégories fils de niveau utilisateur y threads au niveau du noyau en fonction de leur domaine d'exécution. Il existe également des cas où un ou plusieurs threads d'utilisateur correspondent à un ou plusieurs threads du noyau. .

- Fils de niveau utilisateur

Les threads de niveau utilisateur se situent principalement au niveau de l'application, où une application crée ces threads pour soutenir son exécution dans la mémoire principale. Sauf si cela est nécessaire, ces threads travaillent de manière isolée avec les threads du noyau.

Ceux-ci sont plus faciles à créer car ils ne doivent pas faire référence à de nombreux registres et le changement de contexte est beaucoup plus rapide qu'un thread au niveau du noyau.

Le thread au niveau de l'utilisateur peut surtout provoquer des changements au niveau de l'application et le thread au niveau du noyau continue à s'exécuter à son propre rythme.

- Threads au niveau du noyau

Ces threads sont pour la plupart indépendants des processus en cours et sont exécutés par le système d'exploitation.

Ces threads sont requis par le système d'exploitation pour des tâches telles que la gestion de la mémoire, la gestion des processus, etc.

Comme ces threads maintiennent, exécutent et signalent les processus requis par le système d'exploitation, les threads de niveau noyau sont plus coûteux à créer et à gérer et le changement de contexte de ces threads est lent.

La plupart des threads du niveau noyau ne peuvent pas être préemptés par les threads du 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 les threads du noyau

C'est peut-être la partie la plus intéressante. De nombreux threads au niveau de l'utilisateur correspondent à des threads au niveau du noyau, qui à leur tour communiquent avec le noyau.

Certaines des correspondances les plus importantes sont :

One to One

Lorsqu'un thread de niveau utilisateur ne correspond qu'à un seul thread du noyau.

avantages : chaque thread utilisateur correspond à un thread 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 noyau pour interagir et les threads noyaux sont coûteux à créer et à gérer.

De plusieurs à un

Lorsque plusieurs threads d'utilisateur correspondent à un seul thread du noyau.

avantages : il n'est pas nécessaire d'avoir plusieurs threads de noyau puisque des threads d'utilisateur similaires peuvent être mis en correspondance avec un thread de noyau.

inconvénient : même si l'un des threads utilisateur émet un appel système bloquant, tous les autres threads utilisateur mappés à ce thread noyau sont bloqués.

De plus, un bon niveau de simultanéité ne peut pas être atteint puisque le noyau ne traite qu'un seul thread du noyau à la fois.

Beaucoup à beaucoup

Lorsque de nombreux threads utilisateurs correspondent à un nombre égal ou inférieur de threads noyau. C'est le programmeur qui décide du nombre de threads d'utilisateur et du nombre de threads de noyau. Certains des threads d'utilisateur peuvent correspondre à un seul thread de noyau.

avantages : un niveau élevé de concurrence est atteint. Le programmeur peut décider de certains threads potentiellement dangereux qui pourraient émettre un appel système bloquant et les placer dans le mapping un-à-un.

inconvénient : le nombre de threads du noyau, s'il n'est pas décidé avec précaution, peut ralentir le système.

L'autre partie de votre question :

Les threads supportés par le noyau ont accès au kerne et d'autres utilisations non disponibles pour les threads de niveau utilisateur.

Alors, les threads de niveau utilisateur sont-ils simplement des threads créés par le programmeur ? qui utilisent ensuite les threads supportés 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 autres interruptions critiques puisque les threads du noyau sont responsables de l'exécution des processus du système d'exploitation. Les threads utilisateurs n'auront pas accès à certaines de ces fonctionnalités critiques. Par exemple, un éditeur de texte ne pourra jamais tirer sur un thread qui a la capacité de changer l'adresse physique du processus. Mais si nécessaire, un thread d'utilisateur peut se connecter au thread du noyau et émettre certains appels système qu'il ne pourrait pas faire en tant qu'entité indépendante. Le thread du noyau mettrait alors en correspondance cet appel système avec le noyau et exécuterait des actions, si cela était jugé nécessaire.

3voto

Jia Points 1414

Citation d'ici :

Threads au niveau du noyau

Pour rendre la concurrence moins coûteuse, l'aspect exécution du processus est séparé en threads. Ainsi, le système d'exploitation gère maintenant les threads et les processus. Toutes les opérations relatives aux threads sont mises en œuvre dans le noyau et le système d'exploitation planifie tous les threads du système. Les threads gérés par le système d'exploitation sont appelés threads de niveau noyau ou processus légers. NT : Threads Solaris : Processus légers (LWP).

Dans cette méthode, le noyau connaît et gère les threads. Aucun système d'exécution n'est nécessaire dans ce cas. Au lieu d'une table de threads dans chaque processus, le noyau dispose d'une table de threads qui garde la trace de tous les threads du système. En outre, le noyau maintient également la table de processus traditionnelle pour garder la trace des processus. Le noyau des systèmes d'exploitation fournit un appel système pour créer et gérer les threads.

Avantages :

Comme le noyau a une connaissance complète de tous les threads, le planificateur peut décider d'accorder plus de temps à un processus ayant un grand nombre de threads qu'à un processus ayant un petit nombre de threads. Les threads au niveau du noyau sont particulièrement utiles pour les applications qui se bloquent fréquemment.

Inconvénients :

Les threads au niveau du noyau sont lents et inefficaces. Par exemple, les opérations des threads sont des centaines de fois plus lentes que celles des threads de niveau utilisateur. Le noyau doit gérer et planifier les threads ainsi que les processus. Il a besoin d'un bloc de contrôle de thread (TCB) complet pour chaque thread afin de maintenir les informations sur les threads. Il en résulte une surcharge importante et une augmentation de la complexité du noyau.

Fils de niveau utilisateur

Les threads au niveau du noyau rendent la concurrence beaucoup moins chère que les processus, car il y a beaucoup moins d'état à allouer et à initialiser. Cependant, pour une concurrence fine, les threads de niveau noyau souffrent toujours d'une surcharge trop importante. Les opérations des threads nécessitent toujours des appels système. Idéalement, il faudrait que les opérations de threads soient aussi rapides qu'un appel de procédure. Les threads au niveau du noyau doivent être généraux pour répondre aux besoins de tous les programmeurs, langages, moteurs d'exécution, etc. Pour une concurrence aussi fine, nous avons besoin de threads encore plus économiques. Pour que les threads soient rapides et bon marché, ils doivent être implémentés au niveau de l'utilisateur. Les threads de niveau utilisateur sont entièrement gérés par le système d'exécution (bibliothèque de niveau utilisateur). Le noyau ne sait rien des threads de niveau utilisateur et les gère comme s'il s'agissait de processus monofilaires. Les threads de niveau utilisateur sont petits et rapides, chaque thread est représenté par un PC, un registre, une pile et un petit bloc de contrôle de thread. La création d'un nouveau thread, le passage d'un thread à l'autre et la synchronisation des threads se font par appel de procédure, c'est-à-dire sans intervention du noyau. Les threads de niveau utilisateur sont cent fois plus rapides que les threads de niveau noyau.

Avantages :

L'avantage le plus évident de cette technique est qu'un paquetage de threads de niveau utilisateur peut être mis en œuvre sur un système d'exploitation qui ne prend pas en charge les threads. Les threads de niveau utilisateur ne nécessitent pas de modification des systèmes d'exploitation. Représentation simple : Chaque thread est représenté simplement par un PC, des registres, une pile et un petit bloc de contrôle, tous stockés dans l'espace d'adressage du processus utilisateur. Gestion simple : Cela signifie simplement que la création d'un thread, le passage d'un thread à l'autre et la synchronisation entre les threads peuvent tous être effectués sans intervention du noyau. Rapide et efficace : La commutation de threads n'est pas beaucoup plus coûteuse qu'un appel de procédure.

Inconvénients :

Les fils de discussion de niveau utilisateur ne sont pas une solution parfaite, comme pour tout le reste, ils sont un compromis. Comme les threads de niveau utilisateur sont invisibles pour le système d'exploitation, ils ne sont pas bien intégrés à ce dernier. En conséquence, le système d'exploitation peut prendre de mauvaises décisions, comme la programmation d'un processus avec des threads inactifs, le blocage d'un processus dont le thread a initié une entrée/sortie, même si le processus a d'autres threads qui peuvent s'exécuter, et le désordonnancement d'un processus dont un thread détient un verrou. La résolution de ce problème nécessite une communication entre le noyau et le gestionnaire de threads de niveau utilisateur. Il y a un manque de coordination entre les threads et le noyau du système d'exploitation. Par conséquent, le processus dans son ensemble obtient une tranche de temps, qu'il y ait un seul ou 1000 threads dans le processus. C'est à chaque thread de céder le contrôle aux autres threads. Les threads de niveau utilisateur nécessitent un appel système non bloquant, c'est-à-dire un noyau multithread. Sinon, le processus entier sera bloqué dans le noyau, même s'il reste des threads exécutables dans les processus. Par exemple, si un thread provoque un défaut de page, le processus se bloque.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X