2010-09-14 5 views
2

Je pensais pthread utilise clone pour engendrer un nouveau thread dans Linux. Mais si c'est le cas, tous les threads doivent avoir leur propre pid. Sinon, s'ils ont le même pid, les variables globales dans le libc semblent être partagées. Cependant, comme j'ai couru le programme suivant, j'ai eu le même pid mais l'adresse différente de errno.Comment les threads POSIX fonctionnent-ils sous linux?

extern errno; 
void* 
f(void *arg) 
{ 
    printf("%u,%p\n", getpid(), &errno); 
    fflush(stdin); 
    return NULL; 
} 

int 
main(int argc, char **argv) 
{ 
    pthread_t tid; 
    pthread_create(&tid, NULL, f, NULL); 
    printf("%u,%p\n", getpid(), &errno); 
    fflush(stdin); 
    pthread_join(tid, NULL); 
    return 0; 
} 

Ensuite, pourquoi?

Répondre

4

Je ne sais pas exactement comment clone() est utilisé lorsque pthread_create() est appelée. Cela dit, en regardant le clone() man page, il semble qu'il y ait un drapeau appelé CLONE_THREAD qui:

Si CLONE_THREAD est défini, l'enfant est placé dans le même groupe de threads que le processus d'appel . Pour rendre le reste de la discussion de CLONE_THREAD plus lisible, le terme «thread» est utilisé pour se référer aux processus dans un groupe de thread .

groupes de discussion ont été une caractéristique supplémentaire dans Linux 2.4 pour soutenir les fils POSIX notion d'un ensemble de fils qui partagent un PID. En interne, ce PID partagé est l'identificateur de groupe de threads (TGID) pour le groupe . Depuis Linux 2.4, les appels à getpid (2) renvoient le TGID de l'appelant .

Ensuite, il est question d'une fonction gettid() pour obtenir l'ID unique d'un thread individuel dans un processus. Modifier votre code:

#include <stdio.h> 
#include <pthread.h> 
#include <sys/types.h> 
#include <sys/syscall.h> 
#include <unistd.h> 

int errno; 
void* 
f(void *arg) 
{ 
    printf("%u,%p, %u\n", getpid(), &errno, syscall(SYS_gettid)); 
    fflush(stdin); 
    return NULL; 
} 

int 
main(int argc, char **argv) 
{ 
    pthread_t tid; 
    pthread_create(&tid, NULL, f, NULL); 
    printf("%u,%p, %u\n", getpid(), &errno, syscall(SYS_gettid)); 
    fflush(stdin); 
    pthread_join(tid, NULL); 
    return 0; 
} 

(nous assurons d'utiliser « -lpthread »!), Nous pouvons voir que l'ID du sujet individuel est en effet unique, alors que le pid reste le même.

[email protected]:~$ ./a.out 
4109,0x804a034, 4109 
4109,0x804a034, 4110 
+0

Merci beaucoup pour votre aide! Mais qu'en est-il de l'errno * externe * de la glibc? Il est également unique (lorsqu'une variable globale régulière est partagée) – dutor

+0

Ceci est correct - l'espace du noyau "PID" est l'espace utilisateur "TID", et l'espace du noyau "TGID" est l'espace utilisateur "PID". – caf

+0

@dutor: 'errno' n'est pas une simple variable' extern' - il a une manipulation spéciale pour le rendre par thread (il est défini avec une macro: '#define errno (* __ errno_location())' – caf

3
  1. Les variables globales: votre erreur est que errno n'est pas une variable globale, mais une macro qui se développe à un lvalue de type int. En pratique, il s'étend à (*__errno_location()) ou similaire.
  2. getpid est une fonction de bibliothèque qui retourne le processus id dans le sens du processus POSIX, et non le pog clone pog. De nos jours, Linux a la fonctionnalité minimale au niveau du noyau nécessaire pour rendre la conformité proche de POSIX possible en ce qui concerne les threads, mais la plupart dépendent toujours de haineux bidouillages au niveau de la libc de l'espace utilisateur.
+0

Merci! Tu m'as aidé. – dutor

Questions connexes