Je pense que cette partie du clone(2)
La page de manuel peut éclaircir la différence re. le PID :
CLONE_THREAD (depuis Linux 2.4.0-test8)
Si CLONE_THREAD est défini, l'enfant est placé dans le même groupe de threads que le processus appelant.
Les groupes de threads étaient une fonctionnalité ajoutée dans Linux 2.4 pour prendre en charge la notion de threads POSIX d'un ensemble de threads partageant un seul PID. En interne, ce PID partagé est ce que l'on appelle l'identifiant de groupe de threads (TGID) pour le groupe de threads. Depuis Linux2.4, les appels à getpid(2) renvoient le TGID de l'appelant.
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 séparés dans le passé. Fondamentalement, Linux à l'origine n'avait pas de threads dans un processus, juste des processus séparés (avec des PID séparés) qui auraient pu avoir des ressources partagées, comme la mémoire virtuelle ou des descripteurs de fichiers. CLONE_THREAD
et la séparation de l'ID de processus et de l'ID de thread fait que le comportement de Linux ressemble plus à d'autres systèmes et plus aux exigences POSIX dans ce sens. Bien que techniquement, le système d'exploitation n'ait toujours pas d'implémentations séparées pour les threads et les processus.
La gestion du signal était un autre domaine problématique avec l'ancienne implémentation, ceci est décrit 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 été publiée.
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 des threads POSIX sous Linux, appelée LinuxThreads (voir aussi l'article de Wikipedia pour certains).
LinuxThreads avait quelques problèmes de compatibilité avec la norme POSIX - par exemple les threads ne partageant pas de PID - et quelques autres problèmes sérieux. Pour corriger ces défauts, une autre implémentation appelée NPTL (Native POSIX Thread Library) a été dirigée par Red Hat pour ajouter la prise en charge nécessaire du noyau et de la bibliothèque d'espace utilisateur pour atteindre une meilleure conformité POSIX (en prenant de bonnes parties d'un autre projet de réimplémentation concurrent d'IBM appelé NGPT (" Threads Posix de nouvelle génération"), voir l'article de Wikipedia sur NPTL). Les drapeaux supplémentaires ajoutés au clone(2)
appel système (notamment CLONE_THREAD
ce @ikkkachu
souligne dans sa réponse) est probablement la partie la plus évidente des modifications du noyau. La partie espace utilisateur du travail a finalement été intégrée à la bibliothèque GNU C.
Encore aujourd'hui, certains SDK Linux embarqués utilisent l'ancienne implémentation de LinuxThreads car ils utilisent une version à plus petite empreinte mémoire de LibC appelée uClibc (également appelée µClibc), et il a fallu un grand nombre d'années avant que l'implémentation de l'espace utilisateur NPTL de GNU LibC ne soit portée et supposée être l'implémentation de threading POSIX par défaut, car d'une manière générale, ces plates-formes spéciales ne s'efforcent pas de suivre les dernières modes à la vitesse de l'éclair. L'utilisation de l'implémentation LinuxThreads en fonctionnement peut être observée en remarquant qu'en effet, les PID pour différents threads sur ces plates-formes sont différents contrairement à ce que spécifie la norme POSIX - tout comme le livre que vous lisez le décrit. 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.
La page de manuel Linux pthreads(7) fournit un aperçu complet et intéressant des différences entre les deux. Une autre description éclairante, bien que dépassée, des différences est cet article d'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 de Butenhof et les pages de manuel POSIX et Linux sur le sujet. De nombreux tutoriels sur le sujet sont inexacts.
Les threads (espace utilisateur) ne sont pas implémentés en tant que processus en tant que tels sous Linux, en ce sens qu'ils n'ont pas leur propre espace d'adressage privé, ils partagent toujours l'espace d'adressage du processus parent.
Cependant, ces threads sont implémentés pour utiliser le système de comptabilité des processus du noyau, ils reçoivent donc leur propre ID de thread (TID), mais reçoivent le même PID et le même 'ID de groupe de threads' (TGID) que le processus parent - cela contraste avec un fork, où un nouveau TGID et PID sont créés, et le TID est le même que le PID.
Il semble donc que les noyaux récents aient un TID distinct qui peut être interrogé, c'est ce qui est différent pour les threads, un extrait de code approprié pour le montrer dans chacun des main() thread_function() ci-dessus est :
long tid = syscall(SYS_gettid);
printf("%ld\n", tid);
Donc, le code entier avec ceci serait :
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <syscall.h>
void* thread_function (void* arg)
{
long tid = syscall(SYS_gettid);
printf("child thread TID is %ld\n", tid);
fprintf (stderr, "child thread pid is %d\n", (int) getpid ());
/* Spin forever. */
while (1);
return NULL;
}
int main ()
{
pthread_t thread;
long tid = syscall(SYS_gettid);
printf("main TID is %ld\n", tid);
fprintf (stderr, "main thread pid is %d\n", (int) getpid ());
pthread_create (&thread, NULL, &thread_function, NULL);
/* Spin forever. */
while (1);
return 0;
}
Donner un exemple de sortie de :
main TID is 17963
main thread pid is 17963
thread TID is 17964
child thread pid is 17963