65 votes

Comment imprimer pthread_t

Cherché, mais n'ont pas trouvé une réponse satisfaisante.

Je sais qu'il n'y a pas de moyen portable d'imprimer un pthread_t.

Comment le faites-vous dans votre application ?

Mise à jour :

En fait, je n'ai pas besoin de pthread_t, mais d'un petit identifiant numérique, identifiant dans le message de debug les différents threads.

Sur mon système (RHEL 5.3 64 bits), il est défini comme un entier non signé long, donc c'est un grand nombre et juste l'imprimer prend beaucoup de place dans la ligne de debug. Comment gdb attribue-t-il des tids courts ?

40voto

sth Points 91594

Cela affichera une représentation hexadécimale d'un pthread_t, peu importe ce que c'est en réalité :

void fprintPt(FILE *f, pthread_t pt) {
  unsigned char *ptc = (unsigned char*)(void*)(&pt);
  fprintf(f, "0x");
  for (size_t i=0; i

```Pour simplement afficher un petit identifiant pour chaquepthread_t`, quelque chose comme ceci pourrait être utilisé (cette fois en utilisant iostreams) :

void printPt(std::ostream &strm, pthread_t pt) {
  static int nextindex = 0;
  static std::map ids;
  if (ids.find(pt) == ids.end()) {
    ids[pt] = nextindex++;
  }
  strm << ids[pt];
}

En fonction de la plate-forme et de la représentation réelle de pthread_t, il pourrait être nécessaire de définir un operator< ``pour `pthread_t`, car `std::map` a besoin d'un ordre sur les éléments :``

`bool operator<(const pthread_t &left, const pthread_t &right) { ... }` ````

0 votes

+1 pour la portabilité. Mais cette solution donne une représentation pthread_t encore plus longue que ses solutions "non portables" numériques.

0 votes

Gdb assigne des numéros courts. Je serais content avec une solution similaire.

1 votes

R. Pate : Non, ce n'est pas le cas. Notez que le pointeur ptc est déréférencé dans la ligne fprintf.

28voto

Employed Russian Points 50479

GDB utilise l'identifiant du thread (alias pid du noyau, alias LWP) pour les petites quantités sur Linux. Essayez :

  #include 
  ...

    printf("tid = %d\n", syscall(SYS_gettid));

0 votes

Cela retourne LWP. Peut-être que je me trompe mais pthread peut être lié lors de l'exécution à différents LWPs, ne permettant pas d'identifier de manière unique différents pthreads.

6 votes

Sur Linux, il existe une correspondance 1:1 entre pthread_t et LWP. Vous n'obtiendrez jamais le même thread pour rapporter différents LWPs à différents moments de sa vie.

0 votes

Appeler cela LWP est à mon avis faux sur Linux. Parce qu'il n'y a pas de processus "légers" et "lourds". Il y a simplement des tâches, les entités planifiables, qui peuvent partager diverses ressources. Et c'est ce que renvoie cet appel système spécifique à Linux, ID de tâche.

20voto

James McNellis Points 193607

Dans ce cas, cela dépend du système d'exploitation, puisque la norme POSIX ne nécessite plus que pthread_t soit un type arithmétique :

La norme IEEE Std 1003.1-2001/Cor 2-2004, élément XBD/TC2/D6/26 est appliquée, ajoutant pthread_t à la liste des types qui ne sont pas obligatoirement des types arithmétiques, permettant ainsi que pthread_t soit défini comme une structure.

Vous devrez examiner l'en-tête de votre sys/types.h et voir comment pthread_t est implémenté ; ensuite vous pourrez l'afficher comme bon vous semble. Comme il n'y a pas de moyen portable de le faire et que vous ne précisez pas quel système d'exploitation vous utilisez, il n'y a pas grand-chose de plus à dire.

Modifier : pour répondre à votre nouvelle question, GDB attribue ses propres identifiants de thread à chaque démarrage d'un nouveau thread :

À des fins de débogage, gdb associe son propre numéro de thread - toujours un seul entier - avec chaque thread de votre programme.

Si vous cherchez à imprimer un numéro unique à l'intérieur de chaque thread, votre meilleure option serait probablement d'indiquer à chaque thread quel numéro utiliser lors de son démarrage.

0 votes

Une variable de stockage locale au thread fonctionnerait également. Vous pourriez également attendre avant d'attribuer des numéros jusqu'à ce qu'ils soient nécessaires pour un thread donné, mais cela commence à aborder les compromis spécifiques à votre programme.

0 votes

James: "votre option la plus propre serait probablement de dire à chaque fil quel nombre utiliser quand vous le démarrez" - Je viens de passer par pthread_create, et rien ne m'a sauté aux yeux. Comment fait-on cela ?

0 votes

Le quatrième paramètre de pthread_create vous permet de transmettre des données arbitraires à la procédure du thread.

9voto

Roman Nikitchenko Points 3085

D'accord, il semble que ceci est ma réponse finale. Nous avons 2 problèmes réels :

  • Comment obtenir des identifiants de thread uniques plus courts pour le journal.
  • Quoi qu'il en soit, nous devons imprimer l'identifiant pthread_t réel du thread (juste pour lier aux valeurs POSIX au moins).

1. Imprimer l'identifiant POSIX (pthread_t)

Vous pouvez simplement traiter pthread_t comme un tableau d'octets avec des chiffres hexadécimaux imprimés pour chaque octet. Vous n'êtes donc pas limité par un type de taille fixe. Le seul problème est l'ordre des octets. Vous apprécierez probablement si l'ordre de vos octets imprimés est le même que pour un simple "int" imprimé. Voici un exemple pour little-endian et seul l'ordre devrait être inversé (sous define ?) pour big-endian :

#include 
#include 

void print_thread_id(pthread_t id)
{
    size_t i;
    for (i = sizeof(i); i; --i)
        printf("%02x", *(((unsigned char*) &id) + i - 1));
}

int main()
{
    pthread_t id = pthread_self();

    printf("%08x\n", id);
    print_thread_id(id);

    return 0;
}

2. Obtenir un identifiant de thread imprimable plus court

Dans tous les cas proposés, vous devriez traduire l'identifiant de thread réel (POSIX) en index d'une table. Mais il existe 2 approches significativement différentes :

2.1. Suivre les threads.

Vous pouvez suivre les identifiants de threads de tous les threads existants dans une table (leurs appels pthread_create() devraient être enveloppés) et avoir une fonction "surchargée" d'identifiant qui ne vous donne que l'index de la table, pas l'identifiant de thread réel. Ce schéma est également très utile pour tout débogage interne lié aux threads et le suivi des ressources. L'avantage évident est l'effet secondaire de la trace / de l'installation du débogage au niveau du thread avec extension future possible. L'inconvénient est l'exigence de suivre toute création / destruction de thread.

Voici un exemple partiel de pseudocode :

pthread_create_wrapper(...)
{
   id = pthread_create(...)
   add_thread(id);
}

pthread_destruction_wrapper()
{
   /* Le problème principal est qu'il devrait être appelé.
      Les appels pthread_cleanup_*() sont une solution possible. */
   remove_thread(pthread_self());
}

unsigned thread_id(pthread_t known_pthread_id)
{
  return seatch_thread_index(known_pthread_id);
}

/* code utilisateur */
printf("04x", thread_id(pthread_self()));

2.2. Enregistrer simplement un nouvel identifiant de thread.

Pendant l'appel au journal, appelez pthread_self() et recherchez dans la table interne si le thread est connu. Si un thread avec un tel identifiant a été créé, son index est utilisé (ou réutilisé à partir d'un thread précédent, en fait cela n'a pas d'importance car il n'y a pas 2 mêmes ID pour le même moment). Si l'identifiant du thread n'est pas encore connu, une nouvelle entrée est créée donc un nouvel index est généré / utilisé.

L'avantage est la simplicité. L'inconvénient est l'absence de suivi de la création / destruction de thread. Donc pour suivre cela, une mécanique externe est requise.

0 votes

+1 pour la table de recherche. Je considérais également cette approche. Bien que je n'aie pas le contrôle sur tous les threads créés, ils utilisent tous la même fonction pour imprimer un message dans le journal. Je peux donc construire une table de recherche au moment du journal.

0 votes

printf("%08x\n", id); est indéfini lorsque pthread_t n'est pas comme unsigned. Pour éviter cela, utilisez printf("%jx\n", (uintmax_t) id);, fonctionne tant que pthread_t est numérique.

4voto

sharth Points 25625

Sous Centos 5.4 x86_64, pthread_t est un typedef pour un unsigned long.

Par conséquent, nous pourrions faire ceci...

#include 
#include 

int main() {
    pthread_t x;
    printf("%li\n", (unsigned long int) x);
    std::cout << (unsigned long int) x << "\n";
}

0 votes

"%li" est pour un type signé. printf("%lu\n", (unsigned long int) x); est meilleur. Pourquoi ne pas simplement caster vers le type le plus large disponible pour maximiser la portabilité ? printf("%ju\n", (uintmax_t) x);.

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