Si les threads partagent le même PID, comment peuvent-ils être identifiés?

98

J'ai une question liée à l'implémentation des threads sous Linux.

Linux n'a pas de support de thread explicite. Dans l'espace utilisateur, nous pouvons utiliser une bibliothèque de threads (comme NPTL) pour créer des threads. Maintenant, si nous utilisons NPTL, il prend en charge le mappage 1: 1.

Le noyau utilisera la clone()fonction pour implémenter les threads.

Supposons que j'ai créé 4 threads. Cela signifierait alors que:

  • Il y en aura 4 task_struct.
  • À l'intérieur du task_struct, il y aura fourniture de ressources de partage selon les arguments à cloner (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND).

Maintenant, j'ai la requête suivante:

  1. Les 4 threads auront-ils le même PID? Si quelqu'un peut préciser, comment les PID sont partagés.
  2. Comment les différents threads sont-ils identifiés? y a-t-il un concept TID (thread ID)?
SPSN
la source

Réponses:

275

Les quatre threads auront le même PID mais uniquement lorsqu'ils sont vus d'en haut. Ce que vous (en tant qu'utilisateur) appelez un PID n'est pas ce que le noyau (en regardant d'en bas) appelle un PID.

Dans le noyau, chaque thread a son propre ID, appelé PID (bien qu'il serait peut-être plus logique d'appeler cela un TID, ou ID de thread) et ils ont également un TGID (ID de groupe de threads) qui est le PID du thread qui a commencé tout le processus.

De manière simpliste, lorsqu'un nouveau processus est créé, il apparaît comme un thread où le PID et le TGID sont le même (nouveau) numéro.

Lorsqu'un thread démarre un autre thread, ce thread démarré obtient son propre PID (afin que le planificateur puisse le planifier indépendamment) mais il hérite du TGID du thread d'origine.

De cette façon, le noyau peut planifier avec plaisir les threads indépendamment du processus auquel ils appartiennent, tandis que les processus (ID de groupe de threads) vous sont signalés.

La hiérarchie suivante des fils peut aider (a) :

                      USER VIEW
 <-- PID 43 --> <----------------- PID 42 ----------------->
                     +---------+
                     | process |
                    _| pid=42  |_
                  _/ | tgid=42 | \_ (new thread) _
       _ (fork) _/   +---------+                  \
      /                                        +---------+
+---------+                                    | process |
| process |                                    | pid=44  |
| pid=43  |                                    | tgid=42 |
| tgid=43 |                                    +---------+
+---------+
 <-- PID 43 --> <--------- PID 42 --------> <--- PID 44 --->
                     KERNEL VIEW

Vous pouvez voir que le démarrage d'un nouveau processus (à gauche) vous donne un nouveau PID et un nouveau TGID (tous deux définis sur la même valeur), tandis que le démarrage d'un nouveau thread (à droite) vous donne un nouveau PID tout en conservant le même TGID comme thread qui l'a démarré.


(a) Trembler d'émerveillement devant mes impressionnantes compétences graphiques :-)

paxdiablo
la source
20
FYI, getpid()renvoie tgid:, asmlinkage long sys_getpid(void) { return current->tgid;}comme indiqué sur www.makelinux.com/
Duke
6
@Duke - wow, c'est pourquoi je n'ai pas trouvé de gettgid(2)fonction. Et le getpid()ne retournera pas le TID (le "PID" du thread), et c'est là gettid(2)qu'intervient. De cette façon, je peux dire si nous sommes dans le thread principal ou non.
Tomasz Gandor
2
Cela conduit à un autre point intéressant: donc si les threads et les processus sont traités de la même manière dans le noyau (à l'exception du tgid), un processus multi-thread obtiendra en conclusion plus de temps CPU qu'un processus à thread unique, à condition que les deux aient le même priorité et aucun des threads n'est interrompu pour quelque raison que ce soit (comme l'attente d'un mutex).
Aconcagua
1
@Aconcagua, CFS (le planificateur complètement équitable sous Linux) fonctionne généralement de cette façon, mais permet également l'utilisation d'extensions de planificateur de groupe pour faire fonctionner l'équité sur certains groupes de tâches plutôt que sur des tâches individuelles. Je ne l'ai jamais vraiment regardé autrement qu'un rapide coup d'œil.
paxdiablo
`` getpgrp '' pour obtenir l'identifiant du groupe
Pengcheng
2

Les threads sont identifiés à l'aide des PID et TGID (Thread group id). Ils savent également quel thread est un parent de qui donc essentiellement un processus partage son PID avec tous les threads qu'il démarre. Les ID de threads sont généralement gérés par la bibliothèque de threads elle-même (comme pthread, etc ...). Si les 4 threads sont démarrés, ils doivent avoir le même PID. Le noyau lui-même gérera la planification des threads et autres, mais la bibliothèque est celle qui va gérer les threads (qu'ils puissent s'exécuter ou non en fonction de votre utilisation des méthodes de thread join et wait).

Remarque: Ceci provient de mes souvenirs du noyau 2.6.36. Mon travail dans les versions actuelles du noyau est dans la couche I / O, donc je ne sais pas si cela a changé depuis.

Jésus Ramos
la source
-6

Linux fournit à l' fork()appel système la fonctionnalité traditionnelle de duplication d'un processus. Linux offre également la possibilité de créer des threads à l'aide de l' clone()appel système. Cependant, linux ne fait pas la distinction entre les processus et les threads.

SAUNDARYA KUMAR GUPTA
la source