Je suis en train de parcourir ce livre , Advanced Linux Programming de Mark Mitchell, Jeffrey Oldham et Alex Samuel. C'est à partir de 2001, donc un peu vieux. Mais je trouve ça assez bon quand même.
Cependant, je suis arrivé à un point où il s'écarte de ce que mon Linux produit dans la sortie du shell. Sur la page 92 (116 dans le visualiseur), le chapitre 4.5 Implémentation du thread GNU / Linux commence par le paragraphe contenant cette instruction:
L'implémentation de threads POSIX sur GNU / Linux diffère de l'implémentation de thread sur de nombreux autres systèmes de type UNIX de manière importante: sous GNU / Linux, les threads sont implémentés en tant que processus.
Cela semble être un point clé et est illustré plus tard avec un code C. La sortie dans le livre est:
main thread pid is 14608
child thread pid is 14610
Et dans mon Ubuntu 16.04 c'est:
main thread pid is 3615
child thread pid is 3615
ps
la sortie supporte cela.
Je suppose que quelque chose a dû changer entre 2001 et maintenant.
Le sous-chapitre suivant à la page suivante, 4.5.1 Traitement du signal, reprend la déclaration précédente:
Le comportement de l'interaction entre les signaux et les unités d'exécution varie d'un système de type UNIX à un autre. Sous GNU / Linux, le comportement est dicté par le fait que les threads sont implémentés en tant que processus.
Et il semble que cela sera encore plus important plus tard dans le livre. Quelqu'un pourrait-il expliquer ce qui se passe ici?
J'ai déjà vu celui-ci. Les threads du noyau Linux sont-ils vraiment des processus du noyau? , mais ça n’aide pas beaucoup. Je suis confus.
C'est le code C:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void* thread_function (void* arg)
{
fprintf (stderr, "child thread pid is %d\n", (int) getpid ());
/* Spin forever. */
while (1);
return NULL;
}
int main ()
{
pthread_t thread;
fprintf (stderr, "main thread pid is %d\n", (int) getpid ());
pthread_create (&thread, NULL, &thread_function, NULL);
/* Spin forever. */
while (1);
return 0;
}
getpid
renvoie à présent ce qui serait appelé un identifiant de groupe de threads et obtient un identifiant unique pour un processus que vous devez utilisergettid
. Cependant, mis à part le noyau, la plupart des utilisateurs et des outils appellent un processus un groupe de threads, et appellent un processus un thread, par souci de cohérence avec les autres systèmes.Réponses:
Je pense que cette partie de la
clone(2)
page de manuel peut éclaircir la différence re. le PID:L'expression "les threads sont implémentés en tant que processus" fait référence au problème des threads ayant eu des PID distincts dans le passé. À la base, à l'origine, Linux ne comportait pas de threads dans un processus, mais simplement des processus séparés (avec des PID distincts) pouvant avoir des ressources partagées, telles que la mémoire virtuelle ou les descripteurs de fichier.
CLONE_THREAD
et la séparation de l'ID de processus (*) et de l'ID de thread fait que le comportement de Linux ressemble davantage à celui des autres systèmes et davantage à la configuration POSIX requise en ce sens. Bien que techniquement, le système d'exploitation ne dispose toujours pas d'implémentations distinctes pour les threads et les processus.La gestion du signal était un autre domaine problématique de l’ancienne implémentation, elle est décrite plus en détail dans l’ article auquel @FooF fait référence dans sa réponse .
Comme indiqué dans les commentaires, Linux 2.4 est également sorti en 2001, la même année que le livre. Il n’est donc pas surprenant que la nouvelle n’ait pas eu cette impression.
la source
Vous avez raison, en effet "quelque chose a dû changer entre 2001 et maintenant". Le livre que vous lisez décrit le monde selon la première implémentation historique de threads POSIX sous Linux, appelée LinuxThreads (voir aussi l' article de Wikipedia dans certains).
LinuxThreads présentait des problèmes de compatibilité avec le standard POSIX - par exemple, des threads ne partageant pas les PID - et quelques autres problèmes graves. Pour résoudre ces problèmes, Red Hat a piloté une autre implémentation appelée NPTL (Native POSIX Thread Library) afin d’ajouter le support nécessaire à la bibliothèque du noyau et de l’espace utilisateur afin d’améliorer la conformité POSIX (en prenant de bonnes parties d’un autre projet de réimplémentation concurrent appelé IBM par NGPT (" Threads Posix de nouvelle génération "), voir article de Wikipedia sur NPTL ). Les indicateurs supplémentaires ajoutés à l'
clone(2)
appel système (notamment ceCLONE_THREAD
qui est@ikkkachu
indiqué dans sa réponse ) constituent probablement la partie la plus évidente des modifications du noyau. La partie espace de travail du travail a finalement été intégrée à la bibliothèque GNU C.Aujourd'hui encore certains Linux SDKs utilisent l'ancienne implémentation de LinuxThreads embarqués parce qu'ils utilisent version plus petite empreinte mémoire de libc appelé uClibc (aussi appelé μClibc) , et il a fallu beaucoup de années avant la mise en œuvre de l' espace utilisateur NPTL de GNU libc a été porté et assumé comme implémentation POSIX par défaut des threads, car en général ces plates-formes spéciales ne cherchent pas à suivre les dernières modes à la vitesse de l'éclair. Ceci peut être observé en remarquant qu'en réalité, les PID de différents threads sur ces plates-formes sont également différents, contrairement à la norme POSIX, comme le décrit le livre que vous lisez. En fait, une fois que vous avez appelé
pthread_create()
, vous avez soudainement augmenté le nombre de processus de un à trois, car un processus supplémentaire était nécessaire pour maintenir le désordre ensemble.La page de manuel Linux pthreads (7) fournit un aperçu complet et intéressant des différences entre les deux. Un autre instructif, bien que hors-date, la description des différences est ce papier par Ulrich Depper et Ingo Molnar sur la conception de NPTL.
Je vous recommande de ne pas prendre cette partie du livre trop au sérieux. Je recommande plutôt les fils de programmation POSIX et les pages de manuel POSIX et Linux de Butenhof sur le sujet. De nombreux tutoriels sur le sujet sont inexacts.
la source
Les threads (Espace utilisateur) ne sont pas implémentés en tant que processus en tant que tels sous Linux, dans la mesure où ils ne disposent pas de leur propre espace d'adressage privé, ils partagent néanmoins l'espace d'adressage du processus parent.
Cependant, ces threads sont implémentés pour utiliser le système de comptabilisation des processus du noyau. Ils se voient donc attribuer leur propre ID de thread (TID), mais se voient attribuer les mêmes PID et 'ID de groupe de threads' (TGID) que le processus parent. une fourche, où un nouveau TGID et PID sont créés, et le TID est identique au PID.
Il semble donc que les noyaux récents contenaient un TID distinct qui peut être interrogé. C’est ce qui est différent pour les threads. Un extrait de code approprié pour l’afficher dans chacune des fonctions main () thread_function () ci-dessus est:
Donc tout le code avec ceci serait:
Donner un exemple de sortie de:
la source
Fondamentalement, les informations contenues dans votre livre sont historiquement exactes, en raison d’un historique d’implémentation extrêmement regrettable des threads sous Linux. Cette réponse de ma part à une question connexe sur le SO sert également de réponse à votre question:
https://stackoverflow.com/questions/9154671/distinction-between-processes-and-threads-in-linux/9154725#9154725
la source
En interne, il n’existe pas de processus ou de threads dans le noyau Linux. Les processus et les threads sont un concept principalement utilisateur, le noyau lui-même ne voit que des "tâches", qui sont un objet programmable qui peut ne partager aucune, certaines ou toutes ses ressources avec d'autres tâches. Les threads sont des tâches qui ont été configurées pour partager la plupart de ses ressources (espace d'adressage, mmaps, tubes, gestionnaires de fichiers ouverts, sockets, etc.) avec la tâche parente et les processus sont des tâches configurées pour partager des ressources minimales avec la tâche parente .
Lorsque vous utilisez directement l'API Linux ( clone () , au lieu de fork () et pthread_create () ), vous avez beaucoup plus de flexibilité pour définir le volume de ressources à partager ou non, et vous pouvez créer des tâches qui ne sont processus ni entièrement un fil. Si vous utilisez directement ces appels de bas niveau, il est également possible de créer une tâche avec un nouveau TGID (traité comme un processus par la plupart des outils utilisateur) qui partage réellement toutes ses ressources avec la tâche parent, ou inversement, pour créer une tâche avec un TGID partagé (donc traité comme un fil par la plupart des outils utilisateur) qui ne partage aucune ressource avec sa tâche parente.
Tandis que Linux 2.4 implémente TGID, c'est principalement pour le bénéfice de la comptabilité des ressources. De nombreux utilisateurs et outils de l'espace utilisateur trouvent utile de pouvoir regrouper des tâches connexes et de signaler leur utilisation des ressources.
L'implémentation de tâches sous Linux est beaucoup plus fluide que les processus et les vues du monde présentés par les outils de l'espace utilisateur.
la source
En 1996, Linus Torvalds avait déclaré dans un message de la liste de diffusion du noyau que "les threads et les processus sont traités comme un" contexte d'exécution "", ce qui "n'est qu'un conglomérat de tous les états de ce CoE. état, état MMU, autorisations et divers états de communication (fichiers ouverts, gestionnaires de signaux, etc.) ".
Comme vous pouvez le constater, ce programme va générer 25 threads à la fois, chacun dormant pendant 100 secondes avant de rejoindre à nouveau le programme principal. Une fois que les 25 threads ont rejoint le programme, le programme est terminé et se termine.
En utilisant,
top
vous pourrez voir 25 instances du programme "threads2". Mais kidna ennuyeux. La sortie deps auwx
est encore moins intéressante ... MAISps -eLf
ça devient un peu excitant.Vous pouvez voir ici les 26 centres d'excellence créés par le
thread2
programme. Ils partagent tous le même ID de processus (PID) et le même ID de processus parent (PPID), mais chacun a un ID de LWP différent (processus léger), et le nombre de LWP (NLWP) indique qu'il y a 26 centres d'excellence - le programme principal et le 25 fils engendrés par elle.la source
En ce qui concerne Linux, les processus et les threads sont un peu la même chose. Ce qui est de dire qu'ils sont créés avec le même appel système:
clone
.Si vous y réfléchissez, la différence entre les threads et les processus réside dans le fait que les objets du noyau seront partagés par l'enfant et le parent. Pour les processus, ce n’est pas beaucoup: descripteurs de fichiers ouverts, segments de mémoire sur lesquels il n’a pas été écrit, probablement quelques autres auxquels je ne peux penser spontanément. Pour les threads, beaucoup plus d'objets sont partagés, mais pas tous.
Ce qui rapproche les threads et les objets sous Linux, c'est l'
unshare
appel système. Les objets du noyau qui commencent par être partagés peuvent ne pas être partagés après la création du fil. Ainsi, vous pouvez, par exemple, avoir deux threads du même processus qui ont un espace de descripteur de fichier différent (en révoquant le partage des descripteurs de fichier après la création des threads). Vous pouvez le tester vous-même en créant un thread, en appelant lesunshare
deux threads, puis en fermant tous les fichiers et en ouvrant de nouveaux fichiers, canaux ou objets dans les deux threads. Ensuite, regardez dans/proc/your_proc_fd/task/*/fd
et vous verrez que chacuntask
(que vous avez créé en tant que fil) aura des fd différents.En fait, la création de nouveaux threads et de nouveaux processus est une routine de bibliothèque qui appelle en
clone
dessous et spécifie les objets du noyau que le processus nouvellement créétask
va partager avec le processus / thread appelant.la source